Import TBBT (NFS trace replay).
authorMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 23 Apr 2010 19:48:14 +0000 (12:48 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 23 Apr 2010 19:48:14 +0000 (12:48 -0700)
Code downloaded from http://www.ecsl.cs.sunysb.edu/TBBT/.

152 files changed:
TBBT/README [new file with mode: 0644]
TBBT/trace_init/EXAMPLES [new file with mode: 0755]
TBBT/trace_init/INSTALL [new file with mode: 0755]
TBBT/trace_init/NOTES.TXT [new file with mode: 0755]
TBBT/trace_init/commands [new file with mode: 0755]
TBBT/trace_init/common.pl [new file with mode: 0755]
TBBT/trace_init/counts.pl [new file with mode: 0755]
TBBT/trace_init/extract-hierarchy [new file with mode: 0755]
TBBT/trace_init/hier.pl [new file with mode: 0755]
TBBT/trace_init/hier.pl.old [new file with mode: 0755]
TBBT/trace_init/key.pl [new file with mode: 0755]
TBBT/trace_init/latency.pl [new file with mode: 0755]
TBBT/trace_init/nfsdump.pl [new file with mode: 0755]
TBBT/trace_init/nfsscan.pl [new file with mode: 0755]
TBBT/trace_init/nfsscan.txt [new file with mode: 0755]
TBBT/trace_init/ns_loc2gmt.pl [new file with mode: 0755]
TBBT/trace_init/ns_quickview.pl [new file with mode: 0755]
TBBT/trace_init/ns_split.pl [new file with mode: 0755]
TBBT/trace_init/ns_timeagg.pl [new file with mode: 0755]
TBBT/trace_init/ns_tsplit.pl [new file with mode: 0755]
TBBT/trace_init/rfs.pl [new file with mode: 0755]
TBBT/trace_init/rfs.pl.old [new file with mode: 0755]
TBBT/trace_init/rfs.stub.pl [new file with mode: 0755]
TBBT/trace_init/test.cnt [new file with mode: 0644]
TBBT/trace_init/test.fil [new file with mode: 0755]
TBBT/trace_init/userUtils.pl [new file with mode: 0755]
TBBT/trace_play/Makefile.org [new file with mode: 0644]
TBBT/trace_play/README [new file with mode: 0644]
TBBT/trace_play/README.old [new file with mode: 0644]
TBBT/trace_play/agefs [new file with mode: 0755]
TBBT/trace_play/agefs.log [new file with mode: 0644]
TBBT/trace_play/frag_collect [new file with mode: 0755]
TBBT/trace_play/frag_collect_cust [new file with mode: 0755]
TBBT/trace_play/frag_count [new file with mode: 0755]
TBBT/trace_play/frag_count.c [new file with mode: 0644]
TBBT/trace_play/fragment_collect [new file with mode: 0755]
TBBT/trace_play/generate_xmgr [new file with mode: 0755]
TBBT/trace_play/generate_xmgr.c [new file with mode: 0644]
TBBT/trace_play/generate_xmgr.c.old [new file with mode: 0644]
TBBT/trace_play/generic_hash.c [new file with mode: 0644]
TBBT/trace_play/generic_hash.h [new file with mode: 0644]
TBBT/trace_play/hash.h [new file with mode: 0644]
TBBT/trace_play/init_holder.c [new file with mode: 0644]
TBBT/trace_play/nfsd_nfsfh_cust.h [new file with mode: 0644]
TBBT/trace_play/profile.c [new file with mode: 0755]
TBBT/trace_play/profile.h [new file with mode: 0755]
TBBT/trace_play/rfs_3_ops.c [new file with mode: 0644]
TBBT/trace_play/rfs_3_ops.c.old [new file with mode: 0644]
TBBT/trace_play/rfs_assert.h [new file with mode: 0644]
TBBT/trace_play/rfs_c_age.c [new file with mode: 0644]
TBBT/trace_play/rfs_c_age.c.trace_base [new file with mode: 0644]
TBBT/trace_play/rfs_c_age.c.unit_base [new file with mode: 0644]
TBBT/trace_play/rfs_c_age.obsolete.c [new file with mode: 0644]
TBBT/trace_play/rfs_c_dat.c [new file with mode: 0644]
TBBT/trace_play/rfs_c_def.h [new file with mode: 0644]
TBBT/trace_play/rpc/auth.h [new file with mode: 0755]
TBBT/trace_play/rpc/auth_none.c [new file with mode: 0755]
TBBT/trace_play/rpc/auth_unix.c [new file with mode: 0755]
TBBT/trace_play/rpc/auth_unix.h [new file with mode: 0755]
TBBT/trace_play/rpc/authunix_prot.c [new file with mode: 0755]
TBBT/trace_play/rpc/bindresvport.c [new file with mode: 0755]
TBBT/trace_play/rpc/clnt.h [new file with mode: 0755]
TBBT/trace_play/rpc/clnt_generic.c [new file with mode: 0755]
TBBT/trace_play/rpc/clnt_perror.c [new file with mode: 0755]
TBBT/trace_play/rpc/clnt_simple.c [new file with mode: 0755]
TBBT/trace_play/rpc/clnt_tcp.c [new file with mode: 0755]
TBBT/trace_play/rpc/clnt_udp.c [new file with mode: 0755]
TBBT/trace_play/rpc/get_myaddress.c [new file with mode: 0755]
TBBT/trace_play/rpc/getrpcent.c [new file with mode: 0755]
TBBT/trace_play/rpc/getrpcport.c [new file with mode: 0755]
TBBT/trace_play/rpc/netdb.h [new file with mode: 0755]
TBBT/trace_play/rpc/osdep.h [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_clnt.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_clnt.h [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_getmaps.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_getport.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_prot.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_prot.h [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_prot2.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_rmt.c [new file with mode: 0755]
TBBT/trace_play/rpc/pmap_rmt.h [new file with mode: 0755]
TBBT/trace_play/rpc/rpc.h [new file with mode: 0755]
TBBT/trace_play/rpc/rpc_callmsg.c [new file with mode: 0755]
TBBT/trace_play/rpc/rpc_commondata.c [new file with mode: 0755]
TBBT/trace_play/rpc/rpc_dtablesize.c [new file with mode: 0755]
TBBT/trace_play/rpc/rpc_msg.h [new file with mode: 0755]
TBBT/trace_play/rpc/rpc_prot.c [new file with mode: 0755]
TBBT/trace_play/rpc/sfs_ctcp.c [new file with mode: 0755]
TBBT/trace_play/rpc/sfs_cudp.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc.h [new file with mode: 0755]
TBBT/trace_play/rpc/svc_auth.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_auth.h [new file with mode: 0755]
TBBT/trace_play/rpc/svc_auth_unix.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_raw.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_run.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_simple.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_tcp.c [new file with mode: 0755]
TBBT/trace_play/rpc/svc_udp.c [new file with mode: 0755]
TBBT/trace_play/rpc/types.h [new file with mode: 0755]
TBBT/trace_play/rpc/xdr.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr.h [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_array.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_float.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_mem.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_rec.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_reference.c [new file with mode: 0755]
TBBT/trace_play/rpc/xdr_stdio.c [new file with mode: 0755]
TBBT/trace_play/sem.c [new file with mode: 0644]
TBBT/trace_play/sfs.1 [new file with mode: 0755]
TBBT/trace_play/sfs3.full_speed [new file with mode: 0755]
TBBT/trace_play/sfs_2_ops.c [new file with mode: 0644]
TBBT/trace_play/sfs_2_vld.c [new file with mode: 0644]
TBBT/trace_play/sfs_2_xdr.c [new file with mode: 0644]
TBBT/trace_play/sfs_3_ops.c [new file with mode: 0644]
TBBT/trace_play/sfs_3_ops.c.org [new file with mode: 0644]
TBBT/trace_play/sfs_3_vld.c [new file with mode: 0644]
TBBT/trace_play/sfs_3_xdr.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_bio.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_bio.org [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.2thread.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.3thread.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.c [new symlink]
TBBT/trace_play/sfs_c_chd.c.old [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.c.old.2 [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.c.org [new file with mode: 0644]
TBBT/trace_play/sfs_c_chd.work [new file with mode: 0644]
TBBT/trace_play/sfs_c_clk.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_clnt.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_dat.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_def.h [new file with mode: 0644]
TBBT/trace_play/sfs_c_dmp.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_man.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_mnt.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_nfs.h [new file with mode: 0644]
TBBT/trace_play/sfs_c_pnt.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_rnd.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_sig.c [new file with mode: 0644]
TBBT/trace_play/sfs_c_sub.c [new file with mode: 0644]
TBBT/trace_play/sfs_ext_mon [new file with mode: 0755]
TBBT/trace_play/sfs_m_def.h [new file with mode: 0644]
TBBT/trace_play/sfs_m_msg.c [new file with mode: 0644]
TBBT/trace_play/sfs_m_prm.c [new file with mode: 0644]
TBBT/trace_play/sfs_m_snc.c [new file with mode: 0644]
TBBT/trace_play/sfs_m_xdr.c [new file with mode: 0644]
TBBT/trace_play/sfs_mcr [new file with mode: 0755]
TBBT/trace_play/sfs_mgr [new file with mode: 0755]
TBBT/trace_play/sfs_rc [new file with mode: 0755]
TBBT/trace_play/sfs_suchown [new file with mode: 0755]
TBBT/trace_play/sfs_sync.x [new file with mode: 0755]
TBBT/trace_play/t [new file with mode: 0755]
TBBT/trace_play/t.c [new file with mode: 0644]

diff --git a/TBBT/README b/TBBT/README
new file mode 100644 (file)
index 0000000..d2886cf
--- /dev/null
@@ -0,0 +1,50 @@
+1. TBBT Directory Structure
+
+# README:      this file. Introduce the TBBT directory and how to use TBBT.
+# trace_init:  source code for extract file system hierarchy from the trace
+# trace_play:  source code for trace player
+# test:        example of play the EECS Oct 21 1 hour trace. It contains the
+#              original trace file:            anon-lair62-011021-0000.txt
+#              file system hierarchy map:      fh-path-map-play
+#              file system hierarchy:          RFSFS
+#
+
+2. How to use TBBT?
+
+#STEP1: compile the TBBT player, change the executable "sfs3" to be owned
+#       by root 
+
+cd ~nzhu/TBBT/trace_play
+make sfs3
+su - root; chown root:root tplay; exit
+
+#STEP2: copy or link trace file in a directory for trace play
+
+cd TESTDIR
+ln -s ../test/anon-lair62-011021-0000.txt anon-lair62-011021-0000.txt
+
+#STEP3: extract the file system hierarchy from the trace file
+#       There are two outputs: fh-path-map-play and RFSFS
+#      fh-path-map-play is the file system hierarchy map
+#      RFSFS is the actually file system hierarchy, instead of writing
+#       each file to the full length, -S option creates a file system 
+#      hierarchy where all files are of 0 length. This is useful when
+#      for experimental test run or debug run because writing all files
+#      to the full length could be time consuming.
+
+~nzhu/TBBT/trace_init/extract-hierarchy anon-lair62-011021-0000.txt [-S]
+
+#STEP4: copy RFSFS to an exported directory on NFS file server 
+
+scp -r RFSFS server:/export_dir/
+
+#STEP5: pair-up the request and reply packets in the trace. 
+#       The output file name is based on input file with suffix ".pair"
+#       in this example, anon-lair62-011021-0000.txt.pair
+
+sfs3 -pair_trace anon-lair62-011021-0000.txt
+
+
+#STEP6: play the trace against initial file system hierarchy (RFSFS) on server
+
+sfs3 hostname:/export_dir/RFSFS anon-lair62-011021-0000.txt.pair fh-path-map-play 1 0
diff --git a/TBBT/trace_init/EXAMPLES b/TBBT/trace_init/EXAMPLES
new file mode 100755 (executable)
index 0000000..2ed5187
--- /dev/null
@@ -0,0 +1,170 @@
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# $Id: EXAMPLES,v 1.3 2003/07/28 14:27:16 ellard Exp $\r
+#\r
+# For nfsscan version 0.10a (dated 7/25/2003).\r
+\r
+INTRODUCTION\r
+\r
+The usual procedure for analyzing a trace is the following:\r
+\r
+       1.  Use nfsscan to produce a tabularized summary of each\r
+               300-second segment of the trace.  For these examples,\r
+               we'll call this DEFAULT_TABLE.\r
+\r
+               Depending on what you're looking for, the default\r
+               settings of nfsscan might not provide all the info\r
+               you're going to want in the next step.  The default is\r
+               to omit per-client, per-user, per-group, and per-file\r
+               stats and only tally total operation counts.  [THE\r
+               DEFAULTS MAY CHANGE IN A FUTURE RELEASE.]\r
+\r
+       2.  Use ns_timeagg to create a summary of activity in the\r
+               entire trace named SUMMARY_TABLE from DEFAULT_TABLE.\r
+\r
+               Note that almost anything ns_timeagg and ns_split can\r
+               do can also be done directly with nfsscan.  However,\r
+               the implicit goal of ns_timeagg and ns_split is to\r
+               AVOID re-running nfsscan.  It is much faster to\r
+               re-process a table created by nfsscan than it is to\r
+               re-create the table -- the input to nfsscan is\r
+               typically several million (or billion) lines of trace\r
+               data, while the output is usually only a few thousand\r
+               table rows.\r
+\r
+       3.  Use ns_quickview to plot interesting aspects of the\r
+               DEFAULT_TABLE and/or SUMMARY_TABLE.\r
+\r
+       4.  [optional] Use ns_split and/or ns_tsplit to isolate\r
+               interesting parts of DEFAULT_TABLE (such as per-client\r
+               or per-user counts).  Repeat steps 2 and 3 with the\r
+               results.\r
+\r
+       5.  [optional] If steps 2-4 found anything interesting, re-run\r
+               nfsscan with new parameters to take a closer look at\r
+               the trace.\r
+\r
+Examples and discussion of these steps and related topics is given\r
+below.\r
+\r
+For these examples, TRACE is a trace file gathered by nfsdump (or\r
+another tool that creates traces files in the same format), and TABLE.ns\r
+is a file created by nfsscan from TRACE.  The suffix ".ns" is also\r
+used to denote files that contain tables created by nfsscan,\r
+ns_timeagg, ns_split, and ns_tsplit.  Example commandlines always\r
+begin with "%".\r
+\r
+1.  RUNNING NFSSCAN\r
+\r
+2.  CREATING A SUMMARY TABLE\r
+\r
+       To compute a table contsisting of a single row with counts for\r
+       each operation tallied by the nfsscan run, aggregate over time\r
+       with a time length of zero.  (Zero is treated as a special\r
+       time length that includes the entire input table.)\r
+\r
+       % ns_timeagg -t0 TABLE.ns > SUMMARY.ns\r
+\r
+       Note that timeagg will always aggregate over every (except\r
+       time) attribute, so it does not matter whether or not the\r
+       TABLE.ns contains per-client, per-user, per-group, or per-file\r
+       data.  The sum will always be the same.\r
+\r
+       On the other hand, if you want to prevent ns_timeagg from\r
+       aggregating over a particular attribute, specify that\r
+       attribute in the same manner as with nfsscan.  For example, to\r
+       create a table with a single row containing the operation\r
+       count per user:\r
+\r
+       % ns_timeagg -t0 -BU TABLE.ns > SUMMARY.ns\r
+\r
+       Of course, ns_timeagg cannot create data out of thin air.  If\r
+       TABLE.ns does not contain per-user information then -BU will\r
+       have no effect.\r
+\r
+3.  PLOTTING THE DATA\r
+\r
+       To simply plot the total operation count:\r
+\r
+       % ns_quickview TABLE.ns\r
+       % gv qv.ps\r
+\r
+WHICH CLIENT REQUESTS THE MOST OPERATIONS?\r
+\r
+Method:  use nfsscan to tally the per-client operation counts for the\r
+       entire trace file (by using -t0), and then sort by the TOTAL\r
+       op count fields:\r
+\r
+       If TABLE contains per-client information, then this is easy:\r
+\r
+       % ns_timeagg -t0 -BC TABLE | grep -v '^#' \\r
+                       | awk '{print $7, $3}' | sort -nr\r
+\r
+       If TABLE does not contain per-client info, then it's necessary\r
+       to re-run nfsscan:\r
+\r
+       % nfsscan -t0 -BC TRACE | grep -v '^#' \\r
+                       | awk '{print $7, $3}' | sort -nr\r
+\r
+       The output from either command is a two-column table.  The\r
+       first column is the total operation count of each client, and\r
+       the second column is the ID of each client.\r
+\r
+WHICH CLIENT DOES THE MOST READING?\r
+\r
+       If we've already got TABLE, and it contains per-client info,\r
+       then the easiest way is to simply use extract the read count\r
+       column (instead of the TOTAL column) from TABLE:\r
+\r
+       % ns_timeagg -t0 -BC TABLE | grep -v '^#' \\r
+                       | awk '{print $9, $3}' | sort -nr\r
+\r
+       Or, we can nfsscan.  Because we're not interested in anything\r
+       except the read count, we can change the list of operations\r
+       that nfsscan tabulates so that it only counts reads.  (Of course,\r
+       the resulting table is useless for anything except answering\r
+       this particular question, and since nfsscan is expensive to run\r
+       this is probably wasteful.)\r
+\r
+       % nfsscan -t0 -BC -Oread -i TRACE | grep -v '^#' \\r
+                       | awk '{print $7, $3}' | sort -nr\r
+\r
+WHICH CLIENT DOES THE MOST FSSTATS?\r
+\r
+       fsstat is not ordinarily tabulated by nfsscan.  To tell nfsscan\r
+       to keep track of it, we can change the list of operations to consist\r
+       only of fsstat:\r
+\r
+       % nfsscan -t0 -BC -Ofsstat -i TRACE | ...\r
+\r
+       As mentioned in the previous example, it is often wasteful to\r
+       run nfsscan just to get one number.  Another approach is to\r
+       add fsstat to the default list of "interesting" operations, by\r
+       using "+" at the start of the operation list.  This tells nfsscan\r
+       to append the given list of operations to the default list:\r
+\r
+       % nfsscan -t0 -BC -O+fsstat -i TRACE | ...\r
+\r
+       An implication of this is that it's impossible to know what\r
+       each column in the table represents unless you know what\r
+       operations were considered "interesting" for each run of\r
+       nfsscan.  To help with this, nfsscan includes the commandline\r
+       and column titles at the start of each file it creates.\r
+\r
+WHICH USER DOES THE MOST READING?\r
+\r
+       This is exactly like the previous example, except that we use\r
+       -BU instead -BC, to do everything per-user instead of\r
+       per-client.\r
+\r
+WHAT DIRECTORIES ARE HOTTEST?\r
+\r
+       Use the -d option to find the cummulative number of operations\r
+       per directory, then sort the results by operation count.  In\r
+       order to avoid drowning in data you might choose to print\r
+       print only the top 100:\r
+\r
+       % nfsscan -i TRACE -t0 -d | grep '^D' \\r
+                       | awk '{print $7, $5}' | sort -nr | head -100\r
+\r
diff --git a/TBBT/trace_init/INSTALL b/TBBT/trace_init/INSTALL
new file mode 100755 (executable)
index 0000000..6849497
--- /dev/null
@@ -0,0 +1,61 @@
+# $Id: INSTALL,v 1.4 2003/07/28 14:27:16 ellard Exp $\r
+\r
+NFSSCAN INSTALLATION INSTRUCTIONS\r
+\r
+This is version 0.10a of nfsscan, dated 7/25/2003.\r
+\r
+THIS IS A PRELIMINARY RELEASE OF NEW SOFTWARE:\r
+\r
+- THE COMMANDLINE FORMATS MAY EVOLVE RAPIDLY OVER THE NEXT SEVERAL\r
+       RELEASES.\r
+\r
+- DEBUGGING MESSAGES AND WARNINGS MAY APPEAR ON STDERR.  MOST OF THESE\r
+       ARE MEANINGLESS, BUT IF YOU ENCOUNTER A PROBLEM WITH THE\r
+       PROGRAM PLEASE INCLUDE THEM IN YOUR BUG REPORT.\r
\r
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+System Requirements:\r
+\r
+       - You must have PERL 5 (5.005 or later) installed in order to\r
+               use any of these tools.  (None of these tools have\r
+               been tested with PERL 6 or later.)\r
+\r
+       - If you plan to use ns_quickview, make sure that gnuplot is\r
+               installed on your system.\r
+               \r
+               ns_quickview has been tested with gnuplot 3.7 and\r
+               should work with later versions.  If you have problems\r
+               with ns_quickview, please include any diagnostics\r
+               messages from gnuplot and the version of gnuplot with\r
+               your bug report.\r
+\r
+               If gnuplot is not in your path, you must edit\r
+               ns_quickview to set GNUPLOT_PATH to the appropriate\r
+               path after step 2 in the installation instructions.\r
+\r
+Installation:\r
+\r
+1.  Un-tar the distribution into an empty directory.\r
+\r
+2.  Edit the first line of nfsscan and ns_* to point to wherever your\r
+       favorite version of PERL 5 is installed.  If you don't like\r
+       looking at debugging messages, remove the -w from the\r
+       invocation of PERL.\r
+\r
+3.  Make sure that nfsscan and ns_* are executable and that\r
+       all the files are publically readable:\r
+\r
+               chmod 444 *\r
+               chmod 555 nfsscan ns_*\r
+\r
+4.  Read NOTES.TXT for last-minute info or errata for this release,\r
+       and changes from previous releases.\r
+\r
+5.  Read nfsscan.txt and EXAMPLES for more information about how to\r
+       use the tools.\r
+\r
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+PLEASE report bugs, problems or suggestions for improvements to\r
+ellard@eecs.harvard.edu.\r
diff --git a/TBBT/trace_init/NOTES.TXT b/TBBT/trace_init/NOTES.TXT
new file mode 100755 (executable)
index 0000000..040500d
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id: NOTES.TXT,v 1.2 2003/07/28 14:27:16 ellard Exp $
+
+NFSSCAN BUGS
+
+Known bugs for version 0.10a:
+
+- Debugging messages and warnings may appear on stderr.  Most of these
+       are meaningless, but if you encounter a problem with any of
+       the programs program please include them in your bug report.
+
+       Remove the -w from the invocation of PERL (on the first line
+       of each script) if you want to get rid of the PERL warnings.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+PLEASE report bugs, problems or suggestions for improvements to
+ellard@eecs.harvard.edu.
diff --git a/TBBT/trace_init/commands b/TBBT/trace_init/commands
new file mode 100755 (executable)
index 0000000..e71f0b1
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash -x
+
+# to locate a program
+GUNZIP=`whereis gunzip | gawk '{print $2}'`
+echo $GUNZIP
+
+# to run nfsscan
+gunzip -c traces/* | ./nfsscan -f -t0 -o result-total/test > result-total/output 2>&1
+gunzip -c ~traces/anon-lair62-011130-1100.txt.gz | ../nfsscan.pl > output 2>&1
+
+
+
+# post processing of nfsscan
+gawk '{if ($1=="F") print $2, $3, $5, $6 }' output  > output-filename
+gawk '{if ($3!=".") print $0 }' output-filename  > output-filename-known
+
+echo file#; gawk '{if ($1=="F") print $0}' output-filename-known | wc
+echo dir#; gawk '{if ($1=="D") print $0}' output-filename-known | wc
+echo active#; gawk '{if ($2=="A") print $0}' output-filename-known | wc
+echo dead#; gawk '{if ($2=="D") print $0}' output-filename-known | wc
diff --git a/TBBT/trace_init/common.pl b/TBBT/trace_init/common.pl
new file mode 100755 (executable)
index 0000000..5959ee1
--- /dev/null
@@ -0,0 +1,61 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_timeagg,v 1.4 2003/07/10 20:13:31 ellard Exp $\r
+\r
+# Allows rounding of the start time, so that minor clock drift doesn't\r
+# make trace periods appear to begin at funny times (i.e.  one or two\r
+# seconds after midnight, instead of midnight).\r
+#\r
+# This is only meant to help with SMALL amounts of drift.  Trying to\r
+# use this to correct for anything more than a small fraction of the\r
+# sample interval is asking for trouble.\r
+\r
+require 'timelocal.pl';\r
+\r
+sub findStartTime {\r
+       my ($time, $rounding) = @_;\r
+\r
+       my $new_time = int ($time);\r
+\r
+       if (defined $rounding && $rounding != 0) {\r
+               $rounding = int ($rounding);\r
+\r
+               my $leftover = $new_time % $rounding;\r
+\r
+               if ($leftover > $rounding / 2) {\r
+                       $new_time += $rounding;\r
+               }\r
+\r
+               $new_time -= ($new_time % $rounding);\r
+       }\r
+\r
+       return $new_time;\r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/counts.pl b/TBBT/trace_init/counts.pl
new file mode 100755 (executable)
index 0000000..33d7ad9
--- /dev/null
@@ -0,0 +1,103 @@
+#\r
+# Copyright (c) 2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: counts.pl,v 1.9 2003/07/28 14:27:16 ellard Exp $\r
+\r
+package        counts;\r
+\r
+@OpList                = ();\r
+%KeysSeen      = ();\r
+\r
+%OpCounts      = ();\r
+\r
+sub init {\r
+       my (@oplist) = @_;\r
+\r
+       @OpList = @oplist;\r
+}\r
+\r
+sub printTitle {\r
+       my ($out) = @_;\r
+\r
+       my $str = "#C time client fh euid egid";\r
+\r
+       foreach my $op ( @OpList ) {\r
+               $str .= " $op";\r
+       }\r
+       $str .= "\n";\r
+\r
+       print $out $str;\r
+} \r
+\r
+sub printOps {\r
+       my ($start_time, $out) = @_;\r
+       my ($k, $str, $op, $nk);\r
+\r
+       my @allkeys = sort keys %KeysSeen;\r
+\r
+       foreach $k ( @allkeys ) {\r
+               my $tot = "$k,TOTAL";\r
+\r
+               if ($main::OMIT_ZEROS &&\r
+                       (! exists $OpCounts{$tot} || $OpCounts{$tot} == 0)) {\r
+                       next;\r
+               }\r
+\r
+               $str = sprintf ("C %s %s", $start_time, &key::key2str ($k));\r
+\r
+               foreach $op ( @OpList ) {\r
+                       $nk = "$k,$op";\r
+                       if (exists $OpCounts{$nk}) {\r
+                               if ($op eq 'readM' || $op eq 'writeM') {\r
+                                       $str .= sprintf (" %.3f",\r
+                                               $OpCounts{$nk} / (1024 * 1024));\r
+                               }\r
+                               else {\r
+                                       $str .= " $OpCounts{$nk}"\r
+                               }\r
+                       }\r
+                       else {\r
+                               $str .= " 0";\r
+                       }\r
+               }\r
+               $str .= "\n";\r
+               print $out $str;\r
+       }\r
+}\r
+\r
+sub resetOpCounts {\r
+\r
+       # Clear the counts on everything we've seen.\r
+\r
+       foreach my $op ( keys %OpCounts ) {\r
+               $OpCounts{$op} = 0;\r
+       }\r
+}\r
+\r
+1;\r
+\r
diff --git a/TBBT/trace_init/extract-hierarchy b/TBBT/trace_init/extract-hierarchy
new file mode 100755 (executable)
index 0000000..e6b2b9f
--- /dev/null
@@ -0,0 +1,4 @@
+#Usage extract-hierarchy trace_file [-S]
+#nfsscan $1
+echo nfsscan $1
+rfs.pl $2
diff --git a/TBBT/trace_init/hier.pl b/TBBT/trace_init/hier.pl
new file mode 100755 (executable)
index 0000000..3e2ebfc
--- /dev/null
@@ -0,0 +1,715 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: hier.pl,v 1.14 2003/07/26 20:52:03 ellard Exp $\r
+#\r
+# hier.pl - Tools to map out the file system hierarchy.  This is\r
+# accomplished by snooping out the lookup calls.\r
+#\r
+# This is expensive because the hierarchy can require a LOT of space\r
+# to store for a large system with lots of files (especially if files\r
+# come and go).  Don't construct the hierarchy unless you want it --\r
+# and be prepared to prune it from time to time.\r
+\r
+package        hier;\r
+\r
+# Tables used by the outside world:\r
+\r
+%fh2Parent             = ();\r
+%fh2Name               = ();\r
+%fh2Attr               = ();\r
+%fh2AttrOrig           = ();\r
+%parent2fh             = ();\r
+\r
+#RFS: init FS\r
+%rootsName             = ();\r
+%discardFHs = ();\r
+%rootsFHs = ();\r
+#RFS: dependency table\r
+%fhCreate = ();\r
+\r
+%rfsAllFHs = ();\r
+%fhType = (); # we use %fhIsDir instead\r
+$rfsLineNum = 0;\r
+\r
+\r
+\r
+\r
+\r
+\r
+# Library-private tables and variables.\r
+\r
+%pendingCallsXIDnow    = ();\r
+%pendingCallsXIDfh     = ();\r
+%pendingCallsXIDname   = ();\r
+\r
+$nextPruneTime         = -1;\r
+$PRUNE_INTERVAL                = 5 * 60;       # Five minutes.\r
+\r
+sub processLine {\r
+       my ($line, $proto, $op, $xid, $client, $now, $response, $fh_type) = @_;\r
+\r
+       &addRfsAllFHs($line, $proto, $op, $uxid,\r
+                               $now, $response, $fh_type);\r
+\r
+       if ($now > $nextPruneTime) {\r
+               &prunePending ($now - $PRUNE_INTERVAL);\r
+               $nextPruneTime = $now + $PRUNE_INTERVAL;\r
+       }\r
+\r
+       my $uxid = "$client-$xid";\r
+\r
+       # 'lookup', 'create', 'rename', 'delete',\r
+       # 'getattr', 'setattr'\r
+\r
+       #RFS: add mkdir/rmdir/symlink\r
+       if ( $op eq 'lookup' || $op eq 'create' || $op eq 'mkdir' || \r
+            ($op eq 'symlink' && ($proto eq 'C3' || $proto eq 'R3' ) ) ) {\r
+               return (&doLookup ($line, $proto, $op, $uxid,\r
+                               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'rename') {\r
+       }\r
+       elsif ($op eq 'remove' || $op eq 'rmdir') {\r
+               # RFS: why remove these entries? Just let them exist since \r
+               # there is generation number available to distinguish btw removed dir/file \r
+               # and new dir/file with the same inode number.\r
+               #return (&doRemove ($line, $proto, $op, $uxid,\r
+               #               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'getattr' || $op eq 'read' || $op eq 'write'  ||\r
+                ($op eq 'readlink' && ($proto eq 'C3' || $proto eq 'R3' ) ) ) {\r
+               return (&doGetAttr ($line, $proto, $op, $uxid,\r
+                               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'setattr') {\r
+       }\r
+}\r
+\r
+\r
+# get time stamp\r
+\r
+sub getTimeStamp{\r
+       my ($line) = @_;\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               print "getTimeStamp return undef\n";\r
+               return undef;\r
+       }\r
+       else {\r
+               my @l = split (' ', $line, 2);\r
+               return $l[0];\r
+       }\r
+}\r
+\r
+sub addRfsAllFHs {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       my $fh = undef;\r
+       \r
+       my $checkfh = undef;\r
+       $checkfh = nfsd::nfsDumpParseLineField ($line, 'fh');\r
+       if (defined $checkfh) {\r
+               $fh = nfsd::nfsDumpCompressFH ($fh_type, $checkfh);\r
+       }\r
+       \r
+       my $fh2 = undef;\r
+\r
+       if ($op eq 'rename' || $op eq 'link') {\r
+               $checkfh = nfsd::nfsDumpParseLineField ($line, 'fh2');\r
+               if (defined $checkfh) {\r
+                       $fh2 = nfsd::nfsDumpCompressFH ($fh_type, $checkfh);\r
+               }       \r
+       }\r
+\r
+       if (defined $fh) {\r
+               # record the first appearance of the fh\r
+               if ( !exists  $rfsAllFHs{$fh} )  {\r
+                       $rfsAllFHs{$fh} = $rfsLineNum ;\r
+               }\r
+       }\r
+\r
+       if (defined $fh2) {\r
+               if ( !exists  $rfsAllFHs{$fh2} ) {\r
+                       $rfsAllFHs{$fh2} = $rfsLineNum;\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+\r
+sub doLookup {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
+               my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
+\r
+               # All directories have (at least) three names:  the\r
+               # given name, and "." and "..".  We're only interested\r
+               # in the given name.\r
+\r
+               if ($name eq '"."' || $name eq '".."') {\r
+                       return ;\r
+               }\r
+\r
+               my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $fh;\r
+               $pendingCallsXIDname{$uxid} = $name;\r
+       }\r
+       elsif ($proto eq 'R3' || $proto eq 'R2') {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = $pendingCallsXIDfh{$uxid};\r
+               my $name = $pendingCallsXIDname{$uxid};\r
+\r
+               delete $pendingCallsXIDnow{$uxid};\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDname{$uxid};\r
+\r
+               if ($response eq 'OK') {\r
+                       my $cfh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+                       my $type = nfsd::nfsDumpParseLineField ($line, 'ftype');\r
+\r
+                       #if ($type == 2) \r
+                       {\r
+                               $fhIsDir{$cfh} = $type;\r
+                       }\r
+\r
+                       # Original code\r
+                       # $fh2Parent{$cfh} = $pfh;\r
+                       # $fh2Name{$cfh} = $name;\r
+                       # $parent2fh{"$pfh,$name"} = $cfh;\r
+                       # RFS code: in case of the rename, we will record the name of the old name\r
+                       $fh2Parent{$cfh} = $pfh;\r
+                       if (! exists   $fh2Name{$cfh}) {\r
+                               $fh2Name{$cfh} = $name;\r
+                               $parent2fh{"$pfh,$name"} = $cfh;\r
+                       } else {\r
+                               # keep the old name in the fh2Name{$cfh}\r
+                               # and we also add the newname and pfh mapping\r
+                               #$fh2Name{$cfh} = $name;\r
+                               $parent2fh{"$pfh,$name"} = $cfh;\r
+                       }\r
+\r
+                       my ($size, $mode, $atime, $mtime, $ctime, $nlink) =\r
+                                       nfsd::nfsDumpParseLineFields ($line,\r
+                                       'size', 'mode',\r
+                                       'atime', 'mtime', 'ctime', 'nlink');\r
+                       my $ts = getTimeStamp($line);\r
+\r
+                       # RFS: modify here to get/maintain more file attributes\r
+                       # we can just check the ctime and compare it with trace-start-time\r
+                       # to decide whether to create a file/diretory.\r
+                       # atime - last access time of the file\r
+                       # mtime - last modification time of the file\r
+                       # ctime - last file status change time\r
+                       \r
+                       #$fh2Attr{$cfh} = "$size $mode $atime $mtime $ctime";\r
+                       if  (! exists $fh2AttrOrig{$cfh} ) {\r
+                               $fh2AttrOrig{$cfh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
+                       }\r
+                       $fh2Attr{$cfh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
+               }\r
+\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub doRemove {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
+               my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
+\r
+               # All directories have (at least) three names:  the\r
+               # given name, and "." and "..".  We're only interested\r
+               # in the given name.\r
+\r
+               if ($name eq '"."' || $name eq '".."') {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               if (! exists $parent2fh{"$pfh,$name"}) {\r
+                       return ;\r
+               }\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $pfh;\r
+               $pendingCallsXIDname{$uxid} = $name;\r
+       }\r
+       elsif ($proto eq 'R3' || $proto eq 'R2') {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = $pendingCallsXIDfh{$uxid};\r
+               my $name = $pendingCallsXIDname{$uxid};\r
+\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDname{$uxid};\r
+               delete $pendingCallsXIDnow{$uxid};\r
+\r
+               if (! exists $parent2fh{"$pfh,$name"}) {\r
+                       return ;\r
+               }\r
+\r
+               my $cfh = $parent2fh{"$pfh,$name"};\r
+\r
+               if ($response eq 'OK') {\r
+                       if ($op eq 'remove') {\r
+                               printFileInfo ($cfh, 'D');\r
+\r
+                               delete $fh2Parent{$cfh};\r
+                               delete $fh2Name{$cfh};\r
+                               delete $fh2Attr{$cfh};\r
+                               delete $fhs2AttrOrig{$cfg};\r
+                               delete $parent2fh{"$pfh,$name"};\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub doGetAttr {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               #if (nfsd::nfsDumpParseLineField ($line, 'fh')\r
+               #               eq '00018961-57570100-d2440000-61890100') {\r
+               #       printf STDERR "Seen it ($op)\n";\r
+               #}\r
+\r
+               if (! defined $fh) {\r
+                       return ;\r
+               }\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $fh;\r
+# RFS debug code\r
+#my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+#if ($fh eq $wantfh) {\r
+#      print "JIAWU: doGetAttr call $wantfh\n";\r
+#}\r
+       }\r
+       else {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $fh = $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDnow{$uxid};\r
+# RFS debug code\r
+#my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+#if ($fh eq $wantfh) {\r
+#      print "JIAWU: doGetAttr response $wantfh\n";\r
+#}\r
+\r
+               if ($response ne 'OK') {\r
+                       return ;\r
+               }\r
+\r
+               my ($ftype) = nfsd::nfsDumpParseLineFields ($line, 'ftype');\r
+               if (!defined $ftype) {\r
+                       print STDERR "BAD $line";\r
+                       return ;\r
+               }\r
+\r
+               #if ($ftype == 2) \r
+               {\r
+                       $fhIsDir{$fh} = $ftype;\r
+               }\r
+\r
+               #RFS comment: here if fh is a directory, then it will not be add \r
+               # in the two hash table %fh2Attr(%fh2AttrOrig) and %fh2Name\r
+               # if ($ftype != 1) {\r
+               #       return ;\r
+               #}\r
+               if ($ftype != 1) {\r
+                       #return ;\r
+               }\r
+\r
+\r
+               my ($mode, $size, $atime, $mtime, $ctime, $nlink) =\r
+                               nfsd::nfsDumpParseLineFields ($line,\r
+                               'mode', 'size', 'atime', 'mtime', 'ctime', 'nlink');\r
+               my $ts = getTimeStamp($line);\r
+\r
+                       # RFS: modify here to get/maintain more file attributes\r
+                       # we can just check the ctime and compare it with trace-start-time\r
+                       # to decide whether to create a file/diretory.\r
+                       # atime - last access time of the file\r
+                       # mtime - last modification time of the file\r
+                       # ctime - last file status change time\r
+\r
+                       # $fh2Attr{$fh} = "$size $mode $atime $mtime $ctime";\r
+\r
+                       if  (! exists $fh2AttrOrig{$fh} ) {\r
+                               $fh2AttrOrig{$fh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
+                       }\r
+                       $fh2Attr{$fh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
+       }\r
+}\r
+\r
+# Purge all the pending XID records dated earlier than $when (which is\r
+# typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
+# because otherwise missing XID records can pile up, eating a lot of\r
+# memory. \r
+  \r
+sub prunePending {\r
+       my ($when) = @_;\r
+\r
+       foreach my $uxid ( keys %pendingCallsXIDnow ) {\r
+               if ($pendingCallsXIDnow{$uxid} < $when) {\r
+# RFS debug code\r
+my $fh = $pendingCallsXIDfh{$uxid};\r
+my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+if ($fh eq $wantfh) {\r
+       print "JIAWU: prunePending $wantfh\n";\r
+}\r
+#enf RFS\r
+                       delete $pendingCallsXIDnow{$uxid};\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+# Return as much of the path for the given fh as possible.  It may or\r
+# may not reach the root (or the mount point of the file system), but\r
+# right now we don't check.  Usually on busy systems the data is\r
+# complete enough so that most paths are complete back to the mount\r
+# point.\r
+\r
+sub findPath {\r
+       my ($fh) = @_;\r
+       my $isdir = 0;\r
+       my $cnt = 0;\r
+       my $MaxPathLen = 40;\r
+\r
+       if (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) {\r
+               $isdir = 1;\r
+       }\r
+\r
+       my @path = ();\r
+       while ($fh && exists $fh2Name{$fh}) {\r
+               unshift (@path, $fh2Name{$fh});\r
+\r
+               if ( ($fh2Name{$fh} ne '"RFSNN0"' ) ) {\r
+                       if (! exists $fh2Parent{$fh}) {\r
+                               print STDERR "$fh2Name{$fh} ";\r
+                               if ( ($fh2Name{$fh} eq '"RFSNN0"' ) ) {\r
+                                       print STDERR "eq RFSNN0\n";\r
+                               } else {\r
+                                       print STDERR "NOT eq RFSNN0\n";\r
+                               }\r
+                       }\r
+                       if ($fh eq $fh2Parent{$fh}) {\r
+                               unshift (@path, '(LOOP)');\r
+                               last;\r
+                       }\r
+               }\r
+\r
+               if ($cnt++ > $MaxPathLen) {\r
+                       print STDERR "findPath: path too long (> $MaxPathLen)\n";\r
+                       unshift (@path, '(TOO-LONG)');\r
+                       last;\r
+               }\r
+\r
+               $fh = $fh2Parent{$fh};\r
+       }\r
+\r
+       # RFS: append the ~user (fh and !exists $fh2Name{$fh} and type is Directory)\r
+       if ($fh && !exists $fh2Name{$fh} && (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ) {\r
+               if (exists $rootsName{$fh}) {\r
+                       #print "JIAWU: $rootsName{$fh}\n";\r
+                       unshift(@path, $rootsName{$fh});\r
+               } else {\r
+                       print "JIAWU: WARNING! No rootsName for this fh: $fh\n";\r
+                       unshift(@path, $fh);\r
+               }\r
+       } else {\r
+               if ($fh && !exists $fh2Name{$fh} && (!exists $fhIsDir{$fh} || (exists $fhIsDir{$fh} && $fhIsDir{$fh}!=2)) ) {\r
+                       if (exists $discardFHs{$fh}) {\r
+                               open NOATTRDIR, ">>noattrdirdiscard" || die "open noattrdirdiscard failed\n";\r
+                               print NOATTRDIR "$fh DISCARD\n";\r
+                               close NOATTRDIR;\r
+                       } else {\r
+                               # RFS: if a possible fh without attr and name, then regard it as a special root ~/RFSNN0\r
+                               unshift(@path, '"RFSNN0"');\r
+                               $fhIsDir{$fh}=2;\r
+                               $fh2Name{$fh} = '"RFSNN0"';\r
+                               $rootsName{$fh} = '"RFSNN0"';\r
+                               open NOATTRDIR, ">>noattrdir-root";\r
+                               print NOATTRDIR "$fh /RFSNN0/\n";\r
+                               close NOATTRDIR;\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
+       my $str = '';\r
+       $cnt = 0;\r
+       foreach my $p ( @path ) {\r
+               $p =~ s/^.//;\r
+               $p =~ s/.$//;\r
+               $str .= "/$p";\r
+               $cnt++;\r
+       }\r
+\r
+       if ($isdir) {\r
+               $str .= '/';\r
+       }\r
+\r
+       if ($cnt == 0) {\r
+               $str = '.';\r
+       }\r
+\r
+       return ($str, $cnt);\r
+}\r
+\r
+\r
+$total_unknown_fh = 0;\r
+$total_known_fh = 0;\r
+\r
+sub printAll {\r
+       my ($start_time, $out) = @_;\r
+\r
+       my %allfh = ();\r
+       my $fh;\r
+       my $u = 0;\r
+       my $k = 0;\r
+\r
+       # RFS print more information here\r
+       open (OUT_RFS, ">rfsinfo") ||\r
+               die "Can't create $OutFileBaseName.rfs.";\r
+               \r
+       foreach $fh ( keys %fh2Attr ) {\r
+               $allfh{$fh} = 1; \r
+       }\r
+       foreach $fh ( keys %fh2Name ) {\r
+               $allfh{$fh} = 1; \r
+       }\r
+\r
+       #RFS: before printFileInfo, name those roots' name\r
+\r
+       #RFS there are three kind of fh\r
+       # 1. fh/name paired (fh/attr must)\r
+       # 2. fh/attr but no fh/name: type file (discard related operations)\r
+       # 3. fh/attr but no fh/name: type dir (keep as persuedo root)\r
+       $u = $k = 0;\r
+       my $sn=1;\r
+       foreach $fh ( keys %allfh ) {\r
+               if (exists $fh2Parent{$fh} ) {\r
+                       $k++;\r
+               }\r
+               else {\r
+                       $u++;\r
+                       my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
+                       if ($type eq 'D') {\r
+                               $rootsName{$fh} = sprintf("\"RFSNN%d\"", $sn++);\r
+                               $rootsFHs{$fh} = 2;\r
+                       }\r
+                       else {\r
+                               $discardFHs{$fh} = 1;\r
+                       }\r
+               }\r
+       }\r
+       print OUT_RFS "#stat: fh with parent = $k, fh without parent = $u\n";\r
+       $u = keys %rootsFHs;\r
+       print OUT_RFS "#RFS: root fh list($u)\n";\r
+       foreach $fh (keys %rootsName) {\r
+               print OUT_RFS "#RFS: $rootsName{$fh} $fh\n";\r
+       }\r
+       $u = keys %discardFHs;\r
+       print OUT_RFS "#RFS: discard fh list($u)\n";\r
+       print OUT_RFS join("\n", keys %discardFHs, "");\r
+       \r
+\r
+       print $out "#F type state fh path pathcount attrOrig(size,mode,op,atime,mt,ct) attrLast(size,mode,op,at,mt,ct)\n";\r
+\r
+       print $out "#T starttime = $start_time\n";\r
+       foreach $fh ( keys %allfh ) {\r
+               printFileInfoOutputFile ($fh, 'A', $out);\r
+       }\r
+       \r
+       my $numfh2Name = keys %fh2Name;\r
+       my $numfh2Attr = keys %fh2Attr;\r
+       print OUT_RFS "fh2name has $numfh2Name, fh2Attr has $numfh2Attr\n";\r
+\r
+       \r
+       $u = $k = 0;\r
+       foreach $fh ( keys %allfh ) {\r
+               if ( exists $fh2Name{$fh} ) {$k++;}\r
+               else {$u++;}\r
+       }\r
+       print OUT_RFS "#stat: total fh with name = $k, without name = $u\n";\r
+\r
+       print OUT_RFS "#stat: finally, total known fh = $total_known_fh, unknown = $total_unknown_fh\n";\r
+\r
+# Note: fh with name (8303), fh without name (103)\r
+#          root fh list: 18\r
+#          discard fh list: 85\r
+#          known fh (8321): ( fh with name(8303) + root fh list (18) = 8321)\r
+#          unknown fh (85)\r
+#\r
+# All fh from the those data structures: 8321 + 85 = 8303+103\r
+# Or, in keys %allfh\r
+#\r
+# \r
+       print OUT_RFS "#RFS\n";\r
+       close OUT_RFS;  \r
+\r
+       open (MISSED, ">missdiscardfh") ||\r
+                       die "Can't create missdiscardfh.";\r
+       foreach $fh (keys %rfsAllFHs) {\r
+               if ( !exists $allfh{$fh} && \r
+                    ( (defined $fh2Name{$fh}) && ($fh2Name{$fh} ne '"RFSNN0"')) ) {\r
+                       print MISSED "$fh LN: $rfsAllFHs{$fh}\n"\r
+               }\r
+       }\r
+       close MISSED;\r
+\r
+# check for a special fh\r
+#my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+#if ($allfh{$wantfh} == 1) {\r
+#      print OUT_RFS "JIAWU: found $wantfh\n";\r
+#} else {\r
+#      print OUT_RFS "JIAWU: NOT found $wantfh\n";\r
+#}\r
+#foreach $fh ( keys %allfh ) {\r
+#      if ( $fh eq $wantfh ) {\r
+#              print OUT_RFS "JIAWU: found $wantfh\n";\r
+#              printFileInfoOutputFile ($fh, 'JIAWU', *OUT_RFS);\r
+#              last;\r
+#      }\r
+#}\r
+#print OUT_RFS "JIAWU: after \n";\r
+\r
+\r
+}\r
+\r
+sub printFileInfoOutputFile {\r
+       my ($fh, $state, $out) = @_;\r
+\r
+       my ($p, $c) = findPath ($fh);\r
+       \r
+       if ($c == 0) {$total_unknown_fh++;}\r
+       else {$total_known_fh++;}\r
+       \r
+       #my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
+       my $type = $fhIsDir{$fh};\r
+       if (!defined $type) \r
+       {\r
+               print STDERR "unknown ftype(U) for fh: $fh\n"; \r
+               $type = 'U';\r
+       }\r
+       my $attr = (exists $fh2Attr{$fh}) ?\r
+                       $fh2Attr{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
+       my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
+                       $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
+\r
+       print $out "F $type $state $fh $p $c $attrOrig $attr\n";\r
+}\r
+\r
+sub printFileInfo {\r
+       my ($fh, $state) = @_;\r
+\r
+       my ($p, $c) = findPath ($fh);\r
+       \r
+       if ($c == 0) {$total_unknown_fh++;}\r
+       else {$total_known_fh++;}\r
+       \r
+       my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
+       my $attr = (exists $fh2Attr{$fh}) ?\r
+                       $fh2Attr{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
+       my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
+                       $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
+\r
+       print "F $type $state $fh $p $c $attrOrig $attr\n";\r
+}\r
+\r
+#\r
+# The flow to create the dependency table\r
+# \r
+# create(dirfh, name, attr) -->newfh, new attr\r
+# mkdir(dirfh, name, attr) -> newfh, new attr\r
+#\r
+# remove(dirfh, name) --> status\r
+# rmdir(dirfh, name) --> status\r
+# rename(dirfh, name, todirfh, toname) --> status\r
+#\r
+# link(newdirfh, newname, dirfh, name) --> status (newdir/newname=>dir/name)\r
+# syslink(newdirfh, newname, string) --> status (newdir/newname=>"string")\r
+# readlink(fh) --> string\r
+# lookup(dirfh, name) --> fh, attr\r
+# getattr(fh) --> attr\r
+# setattr(fh, attr) --> attr\r
+# read(fh, offset, count) -> attr, data\r
+# write(fh, offset, count, data) --> attr\r
+# readdir(dirfh, cookie, count) --> entries\r
+# statfs(fh) --> status\r
+#\r
+#\r
+#\r
+#\r
+# for each line the trace file: \r
+#      if (op == R2 or R3) continue; #skip the response line\r
+#      switch (the op)\r
+#      {\r
+#      # CREATION OPs:\r
+#      case create:\r
+#      case remove:\r
+#      # DELETE OPs:\r
+#      case mkdir:\r
+#      case rmdir:\r
+#      # other OPs\r
+#\r
+#\r
+#\r
+#\r
+#\r
+1;\r
diff --git a/TBBT/trace_init/hier.pl.old b/TBBT/trace_init/hier.pl.old
new file mode 100755 (executable)
index 0000000..b7f0cf4
--- /dev/null
@@ -0,0 +1,550 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: hier.pl,v 1.14 2003/07/26 20:52:03 ellard Exp $\r
+#\r
+# hier.pl - Tools to map out the file system hierarchy.  This is\r
+# accomplished by snooping out the lookup calls.\r
+#\r
+# This is expensive because the hierarchy can require a LOT of space\r
+# to store for a large system with lots of files (especially if files\r
+# come and go).  Don't construct the hierarchy unless you want it --\r
+# and be prepared to prune it from time to time.\r
+\r
+package        hier;\r
+\r
+# Tables used by the outside world:\r
+\r
+%fh2Parent             = ();\r
+%fh2Name               = ();\r
+%fh2Attr               = ();\r
+%fh2AttrOrig           = ();\r
+%parent2fh             = ();\r
+#RFS\r
+%rootsName             = ();\r
+%discardFHs = ();\r
+%rootsFHs = ();\r
+\r
+\r
+# Library-private tables and variables.\r
+\r
+%pendingCallsXIDnow    = ();\r
+%pendingCallsXIDfh     = ();\r
+%pendingCallsXIDname   = ();\r
+\r
+$nextPruneTime         = -1;\r
+$PRUNE_INTERVAL                = 5 * 60;       # Five minutes.\r
+\r
+sub processLine {\r
+       my ($line, $proto, $op, $xid, $client, $now, $response, $fh_type) = @_;\r
+\r
+       if ($now > $nextPruneTime) {\r
+               &prunePending ($now - $PRUNE_INTERVAL);\r
+               $nextPruneTime = $now + $PRUNE_INTERVAL;\r
+       }\r
+\r
+       my $uxid = "$client-$xid";\r
+\r
+       # 'lookup', 'create', 'rename', 'delete',\r
+       # 'getattr', 'setattr'\r
+\r
+       #RFS: add mkdir/rmdir\r
+       if ($op eq 'lookup' || $op eq 'create' || $op eq 'mkdir') {\r
+               return (&doLookup ($line, $proto, $op, $uxid,\r
+                               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'rename') {\r
+       }\r
+       elsif ($op eq 'remove' || $op eq 'rmdir') {\r
+               # RFS: why remove these entries? Just let them exist since \r
+               # there is generation number available to distinguish btw removed dir/file \r
+               # and new dir/file with the same inode number.\r
+               #return (&doRemove ($line, $proto, $op, $uxid,\r
+               #               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'getattr' || $op eq 'read' || $op eq 'write' ) {\r
+               return (&doGetAttr ($line, $proto, $op, $uxid,\r
+                               $now, $response, $fh_type));\r
+       }\r
+       elsif ($op eq 'setattr') {\r
+       }\r
+}\r
+\r
+sub doLookup {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
+               my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
+\r
+               # All directories have (at least) three names:  the\r
+               # given name, and "." and "..".  We're only interested\r
+               # in the given name.\r
+\r
+               if ($name eq '"."' || $name eq '".."') {\r
+                       return ;\r
+               }\r
+\r
+               my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $fh;\r
+               $pendingCallsXIDname{$uxid} = $name;\r
+       }\r
+       elsif ($proto eq 'R3' || $proto eq 'R2') {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = $pendingCallsXIDfh{$uxid};\r
+               my $name = $pendingCallsXIDname{$uxid};\r
+\r
+               delete $pendingCallsXIDnow{$uxid};\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDname{$uxid};\r
+\r
+               if ($response eq 'OK') {\r
+                       my $cfh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+                       my $type = nfsd::nfsDumpParseLineField ($line, 'ftype');\r
+\r
+                       if ($type == 2) {\r
+                               $fhIsDir{$cfh} = 1;\r
+                       }\r
+\r
+                       $fh2Parent{$cfh} = $pfh;\r
+                       $fh2Name{$cfh} = $name;\r
+                       $parent2fh{"$pfh,$name"} = $cfh;\r
+\r
+                       my ($size, $mode, $atime, $mtime, $ctime) =\r
+                                       nfsd::nfsDumpParseLineFields ($line,\r
+                                       'size', 'mode',\r
+                                       'atime', 'mtime', 'ctime');\r
+\r
+                       # RFS: modify here to get/maintain more file attributes\r
+                       # we can just check the ctime and compare it with trace-start-time\r
+                       # to decide whether to create a file/diretory.\r
+                       # atime - last access time of the file\r
+                       # mtime - last modification time of the file\r
+                       # ctime - last file status change time\r
+                       \r
+                       #$fh2Attr{$cfh} = "$size $mode $atime $mtime $ctime";\r
+                       if  (! exists $fh2AttrOrig{$cfh} ) {\r
+                               $fh2AttrOrig{$cfh} = "$size $mode $op $atime $mtime $ctime";\r
+                       }\r
+                       $fh2Attr{$cfh} = "$size $mode $op $atime $mtime $ctime";\r
+               }\r
+\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub doRemove {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
+               my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
+\r
+               # All directories have (at least) three names:  the\r
+               # given name, and "." and "..".  We're only interested\r
+               # in the given name.\r
+\r
+               if ($name eq '"."' || $name eq '".."') {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               if (! exists $parent2fh{"$pfh,$name"}) {\r
+                       return ;\r
+               }\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $pfh;\r
+               $pendingCallsXIDname{$uxid} = $name;\r
+       }\r
+       elsif ($proto eq 'R3' || $proto eq 'R2') {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $pfh = $pendingCallsXIDfh{$uxid};\r
+               my $name = $pendingCallsXIDname{$uxid};\r
+\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDname{$uxid};\r
+               delete $pendingCallsXIDnow{$uxid};\r
+\r
+               if (! exists $parent2fh{"$pfh,$name"}) {\r
+                       return ;\r
+               }\r
+\r
+               my $cfh = $parent2fh{"$pfh,$name"};\r
+\r
+               if ($response eq 'OK') {\r
+                       if ($op eq 'remove') {\r
+                               printFileInfo ($cfh, 'D');\r
+\r
+                               delete $fh2Parent{$cfh};\r
+                               delete $fh2Name{$cfh};\r
+                               delete $fh2Attr{$cfh};\r
+                               delete $fhs2AttrOrig{$cfg};\r
+                               delete $parent2fh{"$pfh,$name"};\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub doGetAttr {\r
+       my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
+                       nfsd::nfsDumpParseLineField ($line, 'fh'));\r
+\r
+               #if (nfsd::nfsDumpParseLineField ($line, 'fh')\r
+               #               eq '00018961-57570100-d2440000-61890100') {\r
+               #       printf STDERR "Seen it ($op)\n";\r
+               #}\r
+\r
+               if (! defined $fh) {\r
+                       return ;\r
+               }\r
+\r
+               $pendingCallsXIDnow{$uxid} = $now;\r
+               $pendingCallsXIDfh{$uxid} = $fh;\r
+# RFS debug code\r
+my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+if ($fh eq $wantfh) {\r
+       print "JIAWU: doGetAttr call $wantfh\n";\r
+}\r
+       }\r
+       else {\r
+               if (! exists $pendingCallsXIDnow{$uxid}) {\r
+                       return ;\r
+               }\r
+\r
+               my $fh = $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDfh{$uxid};\r
+               delete $pendingCallsXIDnow{$uxid};\r
+# RFS debug code\r
+my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+if ($fh eq $wantfh) {\r
+       print "JIAWU: doGetAttr response $wantfh\n";\r
+}\r
+\r
+               if ($response ne 'OK') {\r
+                       return ;\r
+               }\r
+\r
+               my ($ftype) = nfsd::nfsDumpParseLineFields ($line, 'ftype');\r
+               if (!defined $ftype) {\r
+                       print STDERR "BAD $line";\r
+                       return ;\r
+               }\r
+\r
+               if ($ftype == 2) {\r
+                       $fhIsDir{$fh} = 1;\r
+               }\r
+\r
+               #RFS comment: here if fh is a directory, then it will not be add \r
+               # in the two hash table %fh2Attr(%fh2AttrOrig) and %fh2Name\r
+               # if ($ftype != 1) {\r
+               #       return ;\r
+               #}\r
+               if ($ftype != 1) {\r
+                       #return ;\r
+               }\r
+\r
+\r
+               my ($mode, $size, $atime, $mtime, $ctime) =\r
+                               nfsd::nfsDumpParseLineFields ($line,\r
+                               'mode', 'size', 'atime', 'mtime', 'ctime');\r
+\r
+                       # RFS: modify here to get/maintain more file attributes\r
+                       # we can just check the ctime and compare it with trace-start-time\r
+                       # to decide whether to create a file/diretory.\r
+                       # atime - last access time of the file\r
+                       # mtime - last modification time of the file\r
+                       # ctime - last file status change time\r
+\r
+                       # $fh2Attr{$fh} = "$size $mode $atime $mtime $ctime";\r
+\r
+                       if  (! exists $fh2AttrOrig{$fh} ) {\r
+                               $fh2AttrOrig{$fh} = "$size $mode $op $atime $mtime $ctime";\r
+                       }\r
+                       $fh2Attr{$fh} = "$size $mode $op $atime $mtime $ctime";\r
+       }\r
+}\r
+\r
+# Purge all the pending XID records dated earlier than $when (which is\r
+# typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
+# because otherwise missing XID records can pile up, eating a lot of\r
+# memory. \r
+  \r
+sub prunePending {\r
+       my ($when) = @_;\r
+\r
+       foreach my $uxid ( keys %pendingCallsXIDnow ) {\r
+               if ($pendingCallsXIDnow{$uxid} < $when) {\r
+# RFS debug code\r
+my $fh = $pendingCallsXIDfh{$uxid};\r
+my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+if ($fh eq $wantfh) {\r
+       print "JIAWU: prunePending $wantfh\n";\r
+}\r
+#enf RFS\r
+                       delete $pendingCallsXIDnow{$uxid};\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+# Return as much of the path for the given fh as possible.  It may or\r
+# may not reach the root (or the mount point of the file system), but\r
+# right now we don't check.  Usually on busy systems the data is\r
+# complete enough so that most paths are complete back to the mount\r
+# point.\r
+\r
+sub findPath {\r
+       my ($fh) = @_;\r
+       my $isdir = 0;\r
+       my $cnt = 0;\r
+       my $MaxPathLen = 40;\r
+\r
+       if (exists $fhIsDir{$fh}) {\r
+               $isdir = 1;\r
+       }\r
+\r
+       my @path = ();\r
+       while ($fh && exists $fh2Name{$fh}) {\r
+               unshift (@path, $fh2Name{$fh});\r
+               if ($fh eq $fh2Parent{$fh}) {\r
+                       unshift (@path, '(LOOP)');\r
+                       last;\r
+               }\r
+\r
+               if ($cnt++ > $MaxPathLen) {\r
+                       print STDERR "findPath: path too long (> $MaxPathLen)\n";\r
+                       unshift (@path, '(TOO-LONG)');\r
+                       last;\r
+               }\r
+\r
+               $fh = $fh2Parent{$fh};\r
+       }\r
+\r
+       # RFS: append the ~user (fh and !exists $fh2Name{$fh} and type is Directory)\r
+       if ($fh && !exists $fh2Name{$fh} && exists $fhIsDir{$fh}) {\r
+               if (exists $rootsName{$fh}) {\r
+                       print "JIAWU: $rootsName{$fh}\n";\r
+                       unshift(@path, $rootsName{$fh});\r
+               } else {\r
+                       print "JIAWU: WARNING! No rootsName for this fh: $fh\n";\r
+                       unshift(@path, $fh);\r
+               }\r
+       } else {\r
+               if ($fh && !exists $fh2Name{$fh} && !exists $fhIsDir{$fh}) {\r
+                       if (exists $discardFHs{$fh}) {\r
+                               open NOATTRDIR, ">>noattrdirdiscard";\r
+                               print NOATTRDIR "$fh DISCARD\n";\r
+                               close NOATTRDIR;\r
+                       } else {\r
+                               # RFS: if a possible fh without attr and name, then regard it as a special root ~/RFSNN0\r
+                               unshift(@path, '"RFSNN0"');\r
+                               $fhIsDir{$fh}=1;\r
+                               $fh2Name{$fh} = '"RFSNN0"';\r
+                               $rootsName{$fh} = '"RFSNN0"';\r
+                               open NOATTRDIR, ">>noattrdir-root";\r
+                               print NOATTRDIR "$fh RFSNN0\n";\r
+                               close NOATTRDIR;\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
+       my $str = '';\r
+       $cnt = 0;\r
+       foreach my $p ( @path ) {\r
+               $p =~ s/^.//;\r
+               $p =~ s/.$//;\r
+               $str .= "/$p";\r
+               $cnt++;\r
+       }\r
+\r
+       if ($isdir) {\r
+               $str .= '/';\r
+       }\r
+\r
+       if ($cnt == 0) {\r
+               $str = '.';\r
+       }\r
+\r
+       return ($str, $cnt);\r
+}\r
+\r
+\r
+$total_unknown_fh = 0;\r
+$total_known_fh = 0;\r
+\r
+sub printAll {\r
+       my ($start_time, $out) = @_;\r
+\r
+       my %allfh = ();\r
+       my $fh;\r
+       my $u = 0;\r
+       my $k = 0;\r
+\r
+       # RFS print more information here\r
+       open (OUT_RFS, ">rfsinfo") ||\r
+               die "Can't create $OutFileBaseName.rfs.";\r
+               \r
+       foreach $fh ( keys %fh2Attr ) {\r
+               $allfh{$fh} = 1; \r
+       }\r
+       foreach $fh ( keys %fh2Name ) {\r
+               $allfh{$fh} = 1; \r
+       }\r
+\r
+       #RFS: before printFileInfo, name those roots' name\r
+\r
+       #RFS there are three kind of fh\r
+       # 1. fh/name paired (fh/attr must)\r
+       # 2. fh/attr but no fh/name: type file (discard related operations)\r
+       # 3. fh/attr but no fh/name: type dir (keep as persuedo root)\r
+       $u = $k = 0;\r
+       my $sn=1;\r
+       foreach $fh ( keys %allfh ) {\r
+               if (exists $fh2Parent{$fh} ) {\r
+                       $k++;\r
+               }\r
+               else {\r
+                       $u++;\r
+                       my $type = (exists $fhIsDir{$fh}) ? 'D' : 'F';\r
+                       if ($type eq 'D') {\r
+                               $rootsName{$fh} = sprintf("\"RFSNN%d\"", $sn++);\r
+                               $rootsFHs{$fh} = 1;\r
+                       }\r
+                       else {\r
+                               $discardFHs{$fh} = 1;\r
+                       }\r
+               }\r
+       }\r
+       print OUT_RFS "#stat: fh with parent = $k, fh without parent = $u\n";\r
+       $u = keys %rootsFHs;\r
+       print OUT_RFS "#RFS: root fh list($u)\n";\r
+       foreach $fh (keys %rootsName) {\r
+               print OUT_RFS "#RFS: $rootsName{$fh} $fh\n";\r
+       }\r
+       $u = keys %discardFHs;\r
+       print OUT_RFS "#RFS: discard fh list($u)\n";\r
+       print OUT_RFS join("\n", keys %discardFHs, "");\r
+       \r
+\r
+       print $out "#F type state fh path pathcount attrOrig(size,mode,op,atime,mt,ct) attrLast(size,mode,op,at,mt,ct)\n";\r
+\r
+       print $out "#T starttime = $start_time\n";\r
+       foreach $fh ( keys %allfh ) {\r
+               printFileInfoOutputFile ($fh, 'A', $out);\r
+       }\r
+       \r
+               \r
+       my $numfh2Name = keys %fh2Name;\r
+       my $numfh2Attr = keys %fh2Attr;\r
+       print OUT_RFS "fh2name has $numfh2Name, fh2Attr has $numfh2Attr\n";\r
+       my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
+       if ($allfh{$wantfh} == 1) {\r
+               print OUT_RFS "JIAWU: found $wantfh\n";\r
+       } else {\r
+               print OUT_RFS "JIAWU: NOT found $wantfh\n";\r
+       }\r
+       foreach $fh ( keys %allfh ) {\r
+               if ( $fh eq $wantfh ) {\r
+                       print OUT_RFS "JIAWU: found $wantfh\n";\r
+                       printFileInfoOutputFile ($fh, 'JIAWU', *OUT_RFS);\r
+                       last;\r
+               }\r
+       }\r
+       print OUT_RFS "JIAWU: after \n";\r
+\r
+       \r
+       $u = $k = 0;\r
+       foreach $fh ( keys %allfh ) {\r
+               if ( exists $fh2Name{$fh} ) {$k++;}\r
+               else {$u++;}\r
+       }\r
+       print OUT_RFS "#stat: total known fh = $total_known_fh, unknown = $total_unknown_fh\n";\r
+       print OUT_RFS "#stat: total fh with name = $k, without name = $u\n";\r
+\r
+       print OUT_RFS "#RFS\n";\r
+       close OUT_RFS;  \r
+\r
+}\r
+\r
+sub printFileInfoOutputFile {\r
+       my ($fh, $state, $out) = @_;\r
+\r
+       my ($p, $c) = findPath ($fh);\r
+       \r
+       if ($c == 0) {$total_unknown_fh++;}\r
+       else {$total_known_fh++;}\r
+       \r
+       my $type = (exists $fhIsDir{$fh}) ? 'D' : 'F';\r
+       my $attr = (exists $fh2Attr{$fh}) ?\r
+                       $fh2Attr{$fh} : "-1 -1 -1 -1 -1";\r
+       my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
+                       $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1";\r
+\r
+       print $out "F $type $state $fh $p $c $attrOrig $attr\n";\r
+}\r
+\r
+sub printFileInfo {\r
+       my ($fh, $state) = @_;\r
+\r
+       my ($p, $c) = findPath ($fh);\r
+       \r
+       if ($c == 0) {$total_unknown_fh++;}\r
+       else {$total_known_fh++;}\r
+       \r
+       my $type = (exists $fhIsDir{$fh}) ? 'D' : 'F';\r
+       my $attr = (exists $fh2Attr{$fh}) ?\r
+                       $fh2Attr{$fh} : "-1 -1 -1 -1 -1";\r
+       my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
+                       $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1";\r
+\r
+       print "F $type $state $fh $p $c $attrOrig $attr\n";\r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/key.pl b/TBBT/trace_init/key.pl
new file mode 100755 (executable)
index 0000000..b4eacb0
--- /dev/null
@@ -0,0 +1,122 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: key.pl,v 1.11 2003/07/26 20:52:04 ellard Exp $\r
+\r
+package key;\r
+\r
+sub makeKey {\r
+       my ($line, $proto, $op, $xid, $client, $now) = @_;\r
+       my ($client_id, $fh, $euid, $egid) = ('u', 'u', 'u', 'u');\r
+       my ($uxid) = "$client-$xid";\r
+\r
+       if ($proto eq 'R3' || $proto eq 'R2') {\r
+               if (exists $PendingKeyStr{$uxid}) {\r
+                       return ($PendingKeyStr{$uxid});\r
+               }\r
+               else {\r
+                       return 'u,u,u,u';\r
+               }\r
+       }\r
+\r
+       if ($main::UseClient) {\r
+               $client_id = $client;\r
+               $client_id =~ s/\..*//g\r
+       }\r
+       if ($main::UseFH && $op ne 'null') {\r
+               my $tag = ($op eq 'commit') ? 'file' : 'fh';\r
+\r
+               $fh = nfsd::nfsDumpParseLineField ($line, $tag);\r
+               if (! defined $fh) {\r
+                       print STDERR "undefined fh ($line)\n";\r
+               }\r
+\r
+               $fh = nfsd::nfsDumpCompressFH ($main::FH_TYPE, $fh);\r
+\r
+       }\r
+       if ($main::UseUID && $op ne 'null') {\r
+               $euid = nfsd::nfsDumpParseLineField ($line, 'euid');\r
+       }\r
+       if ($main::UseGID && $op ne 'null') {\r
+               $egid = nfsd::nfsDumpParseLineField ($line, 'egid');\r
+       }\r
+\r
+       my $key = "$client_id,$fh,$euid,$egid";\r
+       $KeysSeen{$key} = 1;\r
+\r
+       $PendingKeyStr{$uxid} = $key;\r
+       $PendingKeyTime{$uxid} = $now;\r
+\r
+       return ($key);\r
+}\r
+\r
+sub key2str {\r
+       my ($key) = @_;\r
+\r
+       my ($client_id, $fh, $euid, $egid) = split (/,/, $key);\r
+\r
+       if ($client_id ne 'u') {\r
+\r
+               # just for aesthetics:\r
+               $client_id = sprintf ("%.8x", hex ($client_id));\r
+               $client_id =~ /^(..)(..)(..)(..)/;\r
+               $client_id = sprintf ("%d.%d.%d.%d",\r
+                               hex ($1), hex ($2), \r
+                               hex ($3), hex ($4)); \r
+               $client_id = sprintf ("%-15s", $client_id);\r
+       }\r
+\r
+       if ($euid ne 'u') {\r
+               $euid = hex ($euid);\r
+       }\r
+       if ($egid ne 'u') {\r
+               $egid = hex ($egid);\r
+       }\r
+\r
+       return ("$client_id $fh $euid $egid");\r
+}\r
+\r
+# Purge all the pending XID records dated earlier than $when (which is\r
+# typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
+# because otherwise missing XID records can pile up, eating a lot of\r
+# memory. \r
+  \r
+sub prunePending {\r
+       my ($when) = @_;\r
+\r
+       foreach my $uxid ( keys %PendingKeyTime ) {\r
+               if ($PendingKeyTime{$uxid} < $when) {\r
+                       delete $PendingKeyTime{$uxid};\r
+                       delete $PendingKeyStr{$uxid};\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/latency.pl b/TBBT/trace_init/latency.pl
new file mode 100755 (executable)
index 0000000..0ba1ecd
--- /dev/null
@@ -0,0 +1,159 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: latency.pl,v 1.8 2003/07/28 14:27:16 ellard Exp $\r
+#\r
+# latency.pl -\r
+\r
+package        latency;\r
+\r
+%PendingOps    = ();\r
+%OpCount       = ();\r
+%OpTime                = ();\r
+%KeysSeen      = ();\r
+\r
+@OpList                = ();\r
+\r
+sub init {\r
+       my (@oplist) = @_;\r
+\r
+       @OpList = @oplist;\r
+}\r
+\r
+# Bugs:  might not recognize the actual response packets.  It's an\r
+# approximation.\r
+\r
+sub update {\r
+       my ($key, $proto, $op, $xid, $client, $now) = @_;\r
+\r
+       my $uxid = "$client-$xid";\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               $PendingOps{$uxid} = $now;\r
+       }\r
+       elsif (exists $PendingOps{$uxid}) {\r
+               my $elapsed = $now - $PendingOps{$uxid};\r
+\r
+               $KeysSeen{$key} = 1;\r
+\r
+               $OpTime{"$key,$op"} += $elapsed;\r
+               $OpCount{"$key,$op"}++;\r
+\r
+               $OpTime{"$key,TOTAL"} += $elapsed;\r
+               $OpCount{"$key,TOTAL"}++;\r
+\r
+               $OpTime{"$key,INTERESTING"} += $elapsed;\r
+               $OpCount{"$key,INTERESTING"}++;\r
+\r
+               delete $PendingOps{$uxid};\r
+       }\r
+}\r
+\r
+sub resetOpCounts {\r
+\r
+       my $k;\r
+\r
+       foreach $k ( keys %OpTime ) {\r
+               $OpTime{$k} = 0.0;\r
+       }\r
+       foreach $k ( keys %OpCount ) {\r
+               $OpCount{$k} = 0;\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub printTitle {\r
+       my $str = "#L time client euid egid fh";\r
+\r
+       foreach my $op ( @OpList ) {\r
+               $str .= " $op-cnt $op-lat";\r
+       }\r
+       $str .= "\n";\r
+\r
+       print $str;\r
+} \r
+\r
+sub printOps {\r
+       my ($start_time, $out) = @_;\r
+       my ($k, $str, $op, $nk, $latms, $cnt);\r
+\r
+       my @allkeys = sort keys %KeysSeen;\r
+\r
+       foreach $k ( @allkeys ) {\r
+               my $tot = "$k,TOTAL";\r
+\r
+               if ($main::OMIT_ZEROS &&\r
+                       (! exists $OpCounts{$tot} || $OpCounts{$tot} == 0)) {\r
+                       next;\r
+               }\r
+\r
+               $str = sprintf ("L %s %s", $start_time, &key::key2str ($k));\r
+\r
+               foreach $op ( @OpList ) {\r
+                       $nk = "$k,$op";\r
+\r
+                       if (exists $OpCount{$nk}) {\r
+                               $cnt = $OpCount{"$k,$op"};\r
+                       }\r
+                       else {\r
+                               $cnt = 0;\r
+                       }\r
+\r
+                       if ($cnt > 0) {\r
+                               $latms = 1000 * $OpTime{$nk} / $cnt;\r
+                       }\r
+                       else {\r
+                               $latms = -1;\r
+                       }\r
+\r
+                       $str .= sprintf (" %d %.4f", $cnt, $latms);\r
+               }\r
+\r
+               print $out "$str\n";\r
+       }\r
+}\r
+\r
+# Purge all the pending XID records dated earlier than $when (which is\r
+# typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
+# because otherwise missing XID records can pile up, eating a lot of\r
+# memory. \r
+  \r
+sub prunePending {\r
+       my ($when) = @_;\r
+\r
+       foreach my $uxid ( keys %PendingOps ) {\r
+               if ($PendingOps{$uxid} < $when) {\r
+                       delete $PendingOps{$uxid};\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/nfsdump.pl b/TBBT/trace_init/nfsdump.pl
new file mode 100755 (executable)
index 0000000..69eca84
--- /dev/null
@@ -0,0 +1,338 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: nfsdump.pl,v 1.5 2003/07/26 20:52:04 ellard Exp $\r
+#\r
+# Utility for dealing with raw nfsdump records.\r
+\r
+package nfsd;\r
+\r
+# If $AllowRisky is set, then allow some optimizations that might be\r
+# "risky" in bizarre situations (but have never been observed to\r
+# actually break anything).  By default, no riskiness is permitted.\r
+\r
+$AllowRisky    = 0;\r
+\r
+# nfsDumpParseLine -- initializes the global associative array\r
+# %nfsd'nfsDumpLine with information about a record from nfsdump. \r
+# Returns an empty list if anything goes wrong.  Otherwise, returns a\r
+# list of the protocol (eg R2, C2, R3, C3), the name of the operation,\r
+# and the xid, the client host ID, the time, and for responses, the\r
+# status (via nfsDumpParseLineHeader).  The reason for this particular\r
+# return list is that these are very frequently-accessed values, so it\r
+# can save time to avoid going through the associative array to access\r
+# them.\r
+#\r
+# All records begin with several fixed fields, and then are followed\r
+# by some number of name/value pairs, and finally some diagnostic\r
+# fields (which are mostly ignored by this routine-- the only\r
+# diagnostic this routine cares about is whether the packet as part of\r
+# a jumbo packet or not.  If so, then 'truncated' is set.)\r
+\r
+sub nfsDumpParseLine {\r
+       my ($line, $total) = @_;\r
+\r
+       my (@rl) = &nfsDumpParseLineHeader ($line);\r
+\r
+       if (@rl && $total) {\r
+               &nfsDumpParseLineBody ($line);\r
+       }\r
+\r
+       return @rl;\r
+}\r
+\r
+sub nfsDumpParseLineBody {\r
+       my ($line) = @_;\r
+       my $i;\r
+       my $client_id;\r
+       my $reseen;\r
+\r
+       undef %nfsDumpLine;\r
+\r
+       # If the line doesn't start with a digit, then it's certainly\r
+       # not properly formed, so bail out immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return undef;\r
+       }\r
+\r
+       my @l = split (' ', $line);\r
+       my $lineLen = @l;\r
+       if ($l[$lineLen - 1] eq 'LONGPKT') {\r
+               splice (@l, $lineLen - 1);\r
+               $nfsDumpLine{'truncated'} = 1;\r
+               $lineLen--;\r
+       }\r
+\r
+       $nfsDumpLine{'time'}    = $l[0];\r
+       $nfsDumpLine{'srchost'} = $l[1];\r
+       $nfsDumpLine{'deshost'} = $l[2];\r
+       $nfsDumpLine{'proto'}   = $l[4];\r
+       $nfsDumpLine{'xid'}     = $l[5];\r
+       $nfsDumpLine{'opcode'}  = $l[6];\r
+       $nfsDumpLine{'opname'}  = $l[7];\r
+\r
+       if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {\r
+               $nfsDumpLine{'status'}  = $l[8];\r
+\r
+               $client_id = $l[2];\r
+               $reseen = 0;\r
+               for ($i = 9; $i < $lineLen - 10; $i += 2) {\r
+                       if (defined $nfsDumpLine{$l[$i]}) {\r
+                               $reseen = 1;\r
+                               $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];\r
+                       }\r
+                       else {\r
+                               $nfsDumpLine{$l[$i]} = $l[$i + 1];\r
+                       }\r
+               }\r
+       }\r
+       else {\r
+               $client_id = $l[1];\r
+               $reseen = 0;\r
+               for ($i = 8; $i < $lineLen - 6; $i += 2) {\r
+                       if (defined $nfsDumpLine{$l[$i]}) {\r
+                               $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];\r
+                               $reseen = 1;\r
+                       }\r
+                       else {\r
+                               $nfsDumpLine{$l[$i]} = $l[$i + 1];\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+# Returns an empty list if anything goes wrong.  Otherwise, returns a\r
+# list of the protocol (eg R2, C2, R3, C3), the name of the operation,\r
+# and the xid, the client host ID, and time, and the response status. \r
+# (For call messages, the status is 'na'.)\r
+\r
+sub nfsDumpParseLineHeader {\r
+       my ($line) = @_;\r
+\r
+       # If the line doesn't start with a digit, then it's certainly\r
+       # not properly formed, so bail out immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return ();\r
+       }\r
+       else {\r
+               my $client_id;\r
+               my $status;\r
+\r
+               my @l = split (' ', $line, 10);\r
+\r
+\r
+               if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {\r
+                       $client_id = $l[2];\r
+                       $status = $l[8];\r
+               }\r
+               else {\r
+                       $client_id = $l[1];\r
+                       $status = 'na';\r
+               }\r
+\r
+               return ($l[4], $l[7], $l[5], $client_id, $l[0], $status);\r
+       }\r
+}\r
+\r
+# nfsDumpParseLineFields -- Just return a subset of the fields,\r
+# without parsing the entire line.\r
+\r
+sub nfsDumpParseLineFields {\r
+       my ($line, @fields) = @_;\r
+       my $i;\r
+\r
+       # If the line doesn't start with a digit, then\r
+       # it's certainly not properly formed, so bail out\r
+       # immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return ();\r
+       }\r
+\r
+       my $rest;\r
+       if ($AllowRisky) {\r
+               $rest = $line;\r
+       }\r
+       else {\r
+               my @foo = split (' ', $line, 9);\r
+               $rest = ' ' . $foo[8];\r
+       }\r
+\r
+       my $fl = @fields;\r
+       my @l = ();\r
+       for ($i = 0; $i < $fl; $i++) {\r
+               my $field = $fields[$i];\r
+\r
+               $rest =~ /\ $field\ +([^\ ]+)/;\r
+               $l[$i] = $1;\r
+       }\r
+\r
+       return (@l);\r
+}\r
+\r
+# nfsDumpParseLineField -- Just return ONE of the fields,\r
+# without parsing the entire line.\r
+\r
+sub nfsDumpParseLineField {\r
+       my ($line, $field) = @_;\r
+\r
+       # If the line doesn't start with a digit, then\r
+       # it's certainly not properly formed, so bail out\r
+       # immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return undef;\r
+       }\r
+\r
+       my $rest;\r
+       if ($AllowRisky) {\r
+               $rest = $line;\r
+       }\r
+       else {\r
+               my @foo = split (' ', $line, 9);\r
+               $rest = ' ' . $foo[8];\r
+       }\r
+\r
+       $rest =~ /\ $field\ +([^\ ]+)/;\r
+       return $1;\r
+}\r
+\r
+# Returns a new file handle that has all the "useful" information as\r
+# the original, but requires less storage space.  File handles\r
+# typically contain quite a bit of redundancy or unused bytes.\r
+#\r
+# This routine only knows about the advfs and netapp formats.  If\r
+# you're using anything else, just use anything else as the mode, and\r
+# the original file handle will be returned.\r
+#\r
+# If you extend this to handle more file handles, please send the new\r
+# code to me (ellard@eecs.harvard.edu) so I can add it to the\r
+# distribution.\r
+\r
+sub nfsDumpCompressFH {\r
+       my ($mode, $fh) = @_;\r
+\r
+       if ($mode eq 'advfs') {\r
+\r
+               # The fh is a long hex string:\r
+               # 8 chars: file system ID\r
+               # 8 chars: apparently unused.\r
+               # 8 chars: unused.\r
+               # 8 chars: inode\r
+               # 8 chars: generation\r
+               # rest of string: mount point (not interesting).\r
+               # So all we do is pluck out the fsid, inode,\r
+               # and generation number, and throw the rest away.\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$1-$4-$5");\r
+       }\r
+       elsif ($mode eq 'netapp') {\r
+\r
+               # Here's the netapp format (from Shane Owara):\r
+               #\r
+               # 4 bytes     mount point file inode number\r
+               # 4 bytes     mount point file generation number\r
+               # \r
+               # 2 bytes     flags\r
+               # 1 byte      snapshot id\r
+               # 1 byte      unused\r
+               #\r
+               # 4 bytes     file inode number\r
+               # 4 bytes     file generation number\r
+               # 4 bytes     volume identifier\r
+               #\r
+               # 4 bytes     export point fileid\r
+               # 1 byte      export point snapshot id\r
+               # 3 bytes     export point snapshot generation number\r
+               #\r
+               # The only parts of this that are interesting are\r
+               # inode, generation, and volume identifier (and probably\r
+               # a lot of the bits of the volume identifier could be\r
+               # tossed, since we don't have many volumes...).\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$4-$5-$6-$1");\r
+       }\r
+       elsif ($mode eq 'RFSNN') {\r
+\r
+               # Here's the netapp format (from Shane Owara):\r
+               #\r
+               # 4 bytes     mount point file inode number\r
+               # 4 bytes     mount point file generation number\r
+               # \r
+               # 2 bytes     flags\r
+               # 1 byte      snapshot id\r
+               # 1 byte      unused\r
+               #\r
+               # 4 bytes     file inode number\r
+               # 4 bytes     file generation number\r
+               # 4 bytes     volume identifier\r
+               #\r
+               # 4 bytes     export point fileid\r
+               # 1 byte      export point snapshot id\r
+               # 3 bytes     export point snapshot generation number\r
+               #\r
+               # The only parts of this that are interesting are\r
+               # inode, generation, and volume identifier (and probably\r
+               # a lot of the bits of the volume identifier could be\r
+               # tossed, since we don't have many volumes...).\r
+               \r
+               # 61890100575701002000000  0009ac710e9ea381  0d24400006189010057570100\r
+               # 61890100575701002000000  0009ac70ed2ea381  0d24400006189010057570100\r
+               # 61890100575701002000000  000479a1e008d782  0d24400006189010057570100\r
+               # Ningning need only 24-39 (or 12-19 bytes)\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$4$5");\r
+       }else {\r
+\r
+               return ($fh);\r
+       }\r
+}\r
+\r
+sub testMain {\r
+       $lineNum = 0;\r
+\r
+       while (<STDIN>) {\r
+               $line = $_;\r
+               $lineNum++;\r
+\r
+               &nfsDumpParseLine ($line);\r
+       }\r
+}\r
+\r
+1;\r
+\r
+# end of nfsdump.pl\r
diff --git a/TBBT/trace_init/nfsscan.pl b/TBBT/trace_init/nfsscan.pl
new file mode 100755 (executable)
index 0000000..fad5216
--- /dev/null
@@ -0,0 +1,682 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: nfsscan,v 1.18 2003/07/28 14:27:16 ellard Exp $\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+require "$ProgDir/nfsdump.pl";\r
+require "$ProgDir/userUtils.pl";\r
+require "$ProgDir/hier.pl";\r
+require "$ProgDir/counts.pl";\r
+require "$ProgDir/latency.pl";\r
+require "$ProgDir/key.pl";\r
+require "$ProgDir/common.pl";\r
+\r
+use Getopt::Std;\r
+\r
+$INTERVAL      = 5 * 60;               # in seconds (5 minutes)\r
+\r
+%KeysSeen      = ();\r
+\r
+@ADD_USERS     = ();\r
+@DEL_USERS     = ();\r
+@ADD_GROUPS    = ();\r
+@DEL_GROUPS    = ();\r
+@ADD_CLIENTS   = ();\r
+@DEL_CLIENTS   = ();\r
+\r
+$DO_COUNTS     = 1;\r
+$DO_LATENCY    = 0;\r
+$DO_FILES      = 0;\r
+$DO_PATHS      = 0;\r
+$DO_SQUEEZE    = 0;\r
+\r
+$FH_TYPE       = 'unknown';\r
+\r
+$END_TIME      = -1;\r
+$START_TIME    = -1;\r
+$NOW           = -1;\r
+$UseClient     = 0;\r
+$UseFH         = 0;\r
+$UseUID                = 0;\r
+$UseGID                = 0;\r
+$OMIT_ZEROS    = 0;\r
+\r
+$OutFileBaseName       = undef;\r
+\r
+$nextPruneTime         = -1;\r
+$PRUNE_INTERVAL                = 1 * 60;       # One minute.\r
+\r
+# &&&\r
+# Is this really the right default set of operations?\r
+\r
+$DEF_OPLIST    = 'read,write,lookup,getattr,access,create,remove';\r
+@OPLIST                = ('TOTAL', 'INTERESTING', \r
+                       split (/,/, $DEF_OPLIST));\r
+%OPARRAY       = ();\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] [trace1 [trace2 ...]]\r
+\r
+If no trace files are specified, then the trace is read from stdin.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-B [CFUG]      Compute per-Client, per-File, per-User, or per-Group info.\r
+\r
+-c c1[,c2]*    Include only activity performed by the specified clients.\r
+\r
+-C c1[,c2]*    Exclude activity performed by the specified clients.\r
+\r
+-d             Compute per-directory statistics.  This implicitly\r
+               enables -BF so that per-file info is computed.\r
+\r
+-f             Do file info tracking.  This implicitly enables -BF so\r
+               that per-File info is computed.\r
+\r
+-F fhtype      Specify the file handle type used by the server.\r
+               (advfs or netapp)\r
+\r
+-g g1[,g2]*    Include only activity performed by the specified groups.\r
+\r
+-G g1[,g2]*    Exclude activity performed by the specified groups.\r
+\r
+-l             Record average operation latency.\r
+\r
+-o basename    Write output to files starting with the specified\r
+               basename.  The "Count" table goes to basename.cnt,\r
+               "Latency" to basename.lat, and "File" to basename.fil.\r
+               The default is to write all output to stdout.\r
+\r
+-O op[,op]*    Specify the list of "interesting" operations.\r
+               The default list is:\r
+\r
+               read,write,lookup,getattr,access,create,remove\r
+\r
+               If the first op starts with +, then the specified list\r
+               of ops is appended to the default list.  The special\r
+               pseudo-ops readM and writeM represent the number of\r
+               bytes read and written, expressed in MB.\r
+\r
+-t interval    Time interval for cummulative statistics (such as\r
+               operation count).  The default is $INTERVAL seconds. \r
+               If set to 0, then the entire trace is processed.  By\r
+               default, time is specified in seconds, but if the last\r
+               character of the interval is any of s, m, h, or d,\r
+               then the interval is interpreted as seconds, minutes,\r
+               hours, or days.\r
+\r
+-u u1[,u2]*    Include only activity performed by the specified users.\r
+\r
+-U u1[,u2]*    Exclude activity performed by the specified users.\r
+\r
+-Z             Omit count and latency lines that have a zero total\r
+               operation count.\r
+.\r
+\r
+\r
+main ();\r
+\r
+sub main {\r
+\r
+       parseArgs ();\r
+\r
+       if ($DO_COUNTS) {\r
+               counts::printTitle (*OUT_COUNTS);\r
+       }\r
+\r
+       if ($DO_LATENCY) {\r
+               latency::printTitle (*OUT_LATENCY);\r
+       }\r
+\r
+       counts::resetOpCounts ();\r
+\r
+       my $cmdbuf = 'rm -f noattrdirdiscard noattrdir-root';\r
+       system($cmdbuf);\r
+\r
+       readTrace ();\r
+}\r
+\r
+sub parseArgs {\r
+\r
+       my $cmdline = "$0 " . join (' ', @ARGV);\r
+\r
+       my $Options = "B:dfF:g:G:hlO:o:t:u:U:SR:Z";\r
+       if (! getopts ($Options)) {\r
+               print STDERR "$0: Incorrect usage.\n";\r
+               print STDERR $Usage;\r
+       exit (1);\r
+       }\r
+       if (defined $opt_h) {\r
+               print $Usage;\r
+               exit (0);\r
+       }\r
+\r
+       #RFS: neednot input arguments\r
+       $opt_o = "test";\r
+       $opt_f = 1;\r
+       $opt_t = 0;\r
+       #$opt_F = 'RFSNN'; # advfs or netapp\r
+\r
+       if (defined $opt_B) {\r
+               $UseClient = ($opt_B =~ /C/);\r
+               $UseFH = ($opt_B =~ /F/);\r
+               $UseUID = ($opt_B =~ /U/);\r
+               $UseGID = ($opt_B =~ /G/);\r
+       }\r
+\r
+       if (defined $opt_o) {\r
+               $OutFileBaseName = $opt_o;\r
+       }\r
+\r
+       if (defined $opt_O) {\r
+               if ($opt_O =~ /^\+(.*)/) {\r
+                       @OPLIST = (@OPLIST, split (/,/, $1));\r
+               }\r
+               else {\r
+                       @OPLIST = ('TOTAL', 'INTERESTING', split (/,/, $opt_O));\r
+               }\r
+               # Error checking?\r
+       }\r
+\r
+       if (defined $opt_l) {\r
+               $DO_LATENCY = 1;\r
+       }\r
+\r
+       if (defined $opt_t) {\r
+               if ($INTERVAL =~ /([0-9]*)([smhd])/) {\r
+                       my $n = $1;\r
+                       my $unit = $2;\r
+\r
+                       if ($unit eq 's') {\r
+                               $INTERVAL = $opt_t;\r
+                       }\r
+                       elsif ($unit eq 'm') {\r
+                               $INTERVAL = $opt_t * 60;\r
+                       }\r
+                       elsif ($unit eq 'h') {\r
+                               $INTERVAL = $opt_t * 60 * 60;\r
+                       }\r
+                       elsif ($unit eq 'd') {\r
+                               $INTERVAL = $opt_t * 24 * 60 * 60;\r
+                       }\r
+               }\r
+               else {\r
+                       $INTERVAL = $opt_t;\r
+               }\r
+       }\r
+\r
+       $DO_PATHS = (defined $opt_d);\r
+       $DO_FILES = (defined $opt_f);\r
+       $DO_SQUEEZE = (defined $opt_S);\r
+       $OMIT_ZEROS = (defined $opt_Z);\r
+\r
+       $TIME_ROUNDING = (defined $opt_R) ? $opt_R : 0;\r
+\r
+       if (defined $opt_F) {\r
+               $FH_TYPE = $opt_F;\r
+       }\r
+\r
+       if (defined $opt_c) {\r
+               @ADD_CLIENTS = split (/,/, $opt_c);\r
+       }\r
+       if (defined $opt_C) {\r
+               @DEL_CLIENTS = split (/,/, $opt_c);\r
+       }\r
+\r
+       if (defined $opt_g) {\r
+               @ADD_GROUPS = groups2gids (split (/,/, $opt_g));\r
+       }\r
+       if (defined $opt_G) {\r
+               @DEL_GROUPS = groups2gids (split (/,/, $opt_G));\r
+       }\r
+\r
+       if (defined $opt_u) {\r
+               @ADD_USERS = logins2uids (split (/,/, $opt_u));\r
+       }\r
+       if (defined $opt_U) {\r
+               @DEL_USERS = logins2uids (split (/,/, $opt_U));\r
+       }\r
+\r
+\r
+       # Now that we know what options the user asked for, initialize\r
+       # things accordingly.\r
+\r
+       if ($DO_PATHS || $DO_FILES) {\r
+               $UseFH = 1;\r
+       }\r
+\r
+       if ($DO_LATENCY) {\r
+               latency::init (@OPLIST);\r
+       }\r
+\r
+       if ($DO_COUNTS) {\r
+               counts::init (@OPLIST);\r
+       }\r
+\r
+       if (defined $OutFileBaseName) {\r
+               if ($DO_COUNTS) {\r
+                       open (OUT_COUNTS, ">$OutFileBaseName.cnt") ||\r
+                               die "Can't create $OutFileBaseName.cnt.";\r
+                       print OUT_COUNTS "#cmdline $cmdline\n";\r
+               }\r
+               if ($DO_LATENCY) {\r
+                       open (OUT_LATENCY, ">$OutFileBaseName.lat") ||\r
+                               die "Can't create $OutFileBaseName.lat.";\r
+                       print OUT_LATENCY "#cmdline $cmdline\n";\r
+               }\r
+               if ($DO_FILES) {\r
+                       open (OUT_FILES, ">$OutFileBaseName.fil") ||\r
+                               die "Can't create $OutFileBaseName.fil.";\r
+                       print OUT_FILES "#cmdline $cmdline\n";\r
+               }\r
+               if ($DO_PATHS) {\r
+                       open (OUT_PATHS, ">$OutFileBaseName.pat") ||\r
+                               die "Can't create $OutFileBaseName.pat.";\r
+                       print OUT_PATHS "#cmdline $cmdline\n";\r
+               }\r
+       }\r
+       else {\r
+               *OUT_COUNTS = STDOUT;\r
+               *OUT_LATENCY = STDOUT;\r
+               *OUT_FILES = STDOUT;\r
+               *OUT_PATHS = STDOUT;\r
+\r
+               print STDOUT "#cmdline $cmdline\n";\r
+       }\r
+\r
+       foreach my $op ( @OPLIST ) {\r
+               $OPARRAY{$op} = 1;\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub readTrace {\r
+       my (@args) = @_;\r
+\r
+       while (my $line = <>) {\r
+\r
+               $hier::rfsLineNum++;\r
+               if ( ($hier::rfsLineNum % 1000) eq 0) {\r
+                       print STDERR "$hier::rfsLineNum\n";\r
+               }\r
+\r
+\r
+               if ($line =~ /SHORT\ PACKET/) {\r
+                       next;\r
+               }\r
+\r
+               my ($proto, $op, $xid, $client, $now, $response) =\r
+                               nfsd::nfsDumpParseLineHeader ($line);\r
+               $NOW = $now;\r
+\r
+               # NOTE:  This next bit of logic requires a little\r
+               # extra attention.  We want to discard lines as\r
+               # quickly as we can if they're not "interesting". \r
+               # However, different lines are interesting in\r
+               # different contexts, so the order of the tests and\r
+               # the manner in which they are interspersed with\r
+               # subroutine calls to pluck info from the lines is\r
+               # very important.\r
+\r
+               # Check whether it is a line that we should prune and\r
+               # ignore, because of the filters.\r
+               \r
+               next if (($op eq 'C3' || $op eq 'C2') &&\r
+                               ! pruneCall ($line, $client));\r
+\r
+               if ($DO_PATHS || $DO_FILES) {\r
+                       hier::processLine ($line,\r
+                                       $proto, $op, $xid, $client,\r
+                                       $now, $response, $FH_TYPE);\r
+               }\r
+\r
+               my $key = key::makeKey ($line, $proto, $op,\r
+                               $xid, $client, $now,\r
+                               $UseClient, $UseFH, $UseUID, $UseGID,\r
+                               $FH_TYPE);\r
+               if (! defined $key) {\r
+                       next ;\r
+               }\r
+               $KeysSeen{$key} = 1;\r
+\r
+               # Count everything towards the total, but only\r
+               # do the rest of the processing for things\r
+               # that are "interesting".\r
+\r
+               if ($proto eq 'C3' || $proto eq 'C2') {\r
+                       $counts::OpCounts{"$key,TOTAL"}++;\r
+                       $counts::KeysSeen{$key} = 1;\r
+\r
+                       next if (! exists $OPARRAY{$op});\r
+\r
+                       $counts::OpCounts{"$key,$op"}++;\r
+                       $counts::OpCounts{"$key,INTERESTING"}++;\r
+               }\r
+\r
+               if ($op eq 'read' && exists $OPARRAY{'readM'}) {\r
+                       doReadSize ($line, $proto, $op, $key, $client, $xid, $response, $now);\r
+               }\r
+\r
+               if ($op eq 'write' && exists $OPARRAY{'writeM'}) {\r
+                       doWriteSize ($line, $proto, $op, $key, $client, $xid, $response, $now);\r
+               }\r
+\r
+               if ($DO_LATENCY) {\r
+                       latency::update ($key, $proto, $op,\r
+                                       $xid, $client, $now);\r
+               }\r
+\r
+               if ($END_TIME < 0) {\r
+                       $START_TIME = findStartTime ($NOW, $TIME_ROUNDING);\r
+                       $END_TIME = $START_TIME + $INTERVAL;\r
+               }\r
+\r
+               # Note that this is a loop, because if the interval is\r
+               # short enough, or the system is very idle (or there's\r
+               # a filter in place that makes it look idle), entire\r
+               # intervals can go by without anything happening at\r
+               # all.  Some tools can get confused if intervals are\r
+               # missing from the table, so we emit them anyway.\r
+\r
+               while (($INTERVAL > 0) && ($NOW >= $END_TIME)) {\r
+                       printAll ($START_TIME);\r
+\r
+                       counts::resetOpCounts ();\r
+                       latency::resetOpCounts ();\r
+\r
+                       $START_TIME += $INTERVAL;\r
+                       $END_TIME = $START_TIME + $INTERVAL;\r
+               }\r
+\r
+               if ($now > $nextPruneTime) {\r
+                       key::prunePending ($now - $PRUNE_INTERVAL);\r
+                       latency::prunePending ($now - $PRUNE_INTERVAL);\r
+\r
+                       prunePending ($now - $PRUNE_INTERVAL);\r
+\r
+                       $nextPruneTime = $now + $PRUNE_INTERVAL;\r
+               }\r
+       }\r
+\r
+       # Squeeze out the last little bit, if there's anything that we\r
+       # counted but did not emit.  If DO_SQUEEZE is true, then\r
+       # always do this.  Otherwise, only squeeze out the results of\r
+       # the last interval if the interval is "almost" complete (ie\r
+       # within 10 seconds of the end).\r
+\r
+       if (($NOW > $START_TIME) && ($DO_SQUEEZE || (($END_TIME - $NOW) < 10))) {\r
+               printAll ($START_TIME);\r
+               counts::resetOpCounts ();\r
+       }\r
+\r
+       print "#T endtime = $NOW\n";\r
+\r
+}\r
+\r
+sub printAll {\r
+       my ($start_time) = @_;\r
+\r
+       if ($DO_COUNTS) {\r
+               counts::printOps ($start_time, *OUT_COUNTS);\r
+       }\r
+\r
+       if ($DO_LATENCY) {\r
+               latency::printOps ($start_time, *OUT_LATENCY);\r
+       }\r
+\r
+       if ($DO_FILES) {\r
+               hier::printAll ($start_time, *OUT_FILES);\r
+       }\r
+\r
+       if ($DO_PATHS) {\r
+               printPaths ($start_time, *OUT_PATHS);\r
+       }\r
+}\r
+\r
+sub pruneCall {\r
+       my ($line, $client) = @_;\r
+\r
+       if (@ADD_USERS > 0 || @DEL_USERS > 0) {\r
+               my $c_uid = nfsd::nfsDumpParseLineField ($line, 'euid');\r
+               if (! defined ($c_uid)) {\r
+                       return 0;\r
+               }\r
+               $c_uid = hex ($c_uid);\r
+\r
+               if (@ADD_USERS && !grep (/^$c_uid$/, @ADD_USERS)) {\r
+                       return 0;\r
+               }\r
+               if (@DEL_USERS && grep (/^$c_uid$/, @DEL_USERS)) {\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       if (@ADD_GROUPS > 0 || @DEL_GROUPS > 0) {\r
+               my $c_gid = nfsd::nfsDumpParseLineField ($line, 'egid');\r
+               if (! defined ($c_gid)) {\r
+                       return 0;\r
+               }\r
+               $c_gid = hex ($c_gid);\r
+\r
+               if (@ADD_GROUPS && !grep (/^$c_gid$/, @ADD_GROUPS)) {\r
+                       return 0;\r
+               }\r
+               if (@DEL_GROUPS && grep (/^$c_gid$/, @DEL_GROUPS)) {\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       if (@ADD_CLIENTS > 0 || @DEL_CLIENTS > 0) {\r
+               if (@ADD_CLIENTS && !grep (/^$client$/, @ADD_CLIENTS)) {\r
+                       return 0;\r
+               }\r
+               if (@DEL_CLIENTS && grep (/^$client$/, @DEL_CLIENTS)) {\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+%PathOpCounts  = ();\r
+%PathsSeen     = ();\r
+\r
+sub buildDirPath {\r
+       my ($fh, $key) = @_;\r
+       my $pfh;\r
+       my $cnt;\r
+\r
+       foreach my $op ( @OPLIST ) {\r
+               if (exists $counts::OpCounts{"$key,$op"}) {\r
+                       $cnt = $counts::OpCounts{"$key,$op"};\r
+               }\r
+               else {\r
+                       $cnt = 0;\r
+               }\r
+               $PathOpCounts{"$fh,$op"} = $cnt;\r
+\r
+               $PathsSeen{$fh} = 1;\r
+\r
+               $pfh = $fh;\r
+               my $len = 0;\r
+               while (defined ($pfh = $hier::fh2Parent{$pfh})) {\r
+\r
+                       if ($len++ > 20) {\r
+                               print "Really long path ($fh)\n";\r
+                               last;\r
+                       }\r
+\r
+                       if (exists $PathOpCounts{"$pfh,$op"}) {\r
+                               $PathOpCounts{"$pfh,$op"} += $cnt;\r
+                       }\r
+                       else {\r
+                               $PathOpCounts{"$pfh,$op"} = $cnt;\r
+                       }\r
+                       $PathsSeen{$pfh} = 1;\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
+sub printPaths {\r
+       my ($start_time, $out) = @_;\r
+\r
+       my $str = "#D time Dir/File dircnt path fh";\r
+       foreach my $op ( @OPLIST ) {\r
+               $str .= " $op";\r
+       }\r
+       $str .= "\n";\r
+\r
+       print $out $str;\r
+\r
+       undef %PathsSeen;\r
+\r
+       foreach my $key ( keys %KeysSeen ) {\r
+               my ($client_id, $fh, $euid, $egid) = split (/,/, $key);\r
+\r
+               buildDirPath ($fh, $key);\r
+       }\r
+\r
+       foreach my $fh ( keys %PathsSeen ) {\r
+               my ($path, $cnt) = hier::findPath ($fh);\r
+\r
+               if ($cnt == 0) {\r
+                       $path = ".";\r
+               }\r
+\r
+               my $type = (exists $hier::fhIsDir{$fh} && $hier::fhIsDir{$fh}==2) ? 'D' : 'F';\r
+\r
+               my $str = "$cnt $type $path $fh ";\r
+\r
+               foreach my $op ( @OPLIST ) {\r
+                       my $cnt;\r
+\r
+                       if (exists $PathOpCounts{"$fh,$op"}) {\r
+                               $cnt = $PathOpCounts{"$fh,$op"};\r
+                       }\r
+                       else {\r
+                               print "Missing $fh $op\n";\r
+                               $cnt = 0;\r
+                       }\r
+\r
+                       $str .= " $cnt";\r
+\r
+                       $PathOpCounts{"$fh,$op"} = 0;   # &&& reset\r
+               }\r
+\r
+               print $out "D $start_time $str\n";\r
+       }\r
+}\r
+\r
+%uxid2key      = ();\r
+%uxid2time     = ();\r
+\r
+sub doReadSize {\r
+       my ($line, $proto, $op, $key, $client, $xid, $response, $time) = @_;\r
+\r
+       my $uxid = "$client-$xid";\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+               $uxid2time{$uxid} = $time;\r
+               $uxid2key{$uxid} = $key;\r
+       }\r
+       else {\r
+               if (! exists $uxid2key{$uxid}) {\r
+                       return ;\r
+               }\r
+               if ($response ne 'OK') {\r
+                       return ;\r
+               }\r
+\r
+               $key = $uxid2key{$uxid};\r
+               my $count = nfsd::nfsDumpParseLineField ($line, 'count');\r
+               $count = hex ($count);\r
+\r
+               delete $uxid2key{$uxid};\r
+               delete $uxid2time{$uxid};\r
+\r
+               $counts::OpCounts{"$key,readM"} += $count;\r
+       }\r
+}\r
+\r
+# Note that we always just assume that writes succeed, because on most\r
+# systems they virtually always do.  If you're tracing a system where\r
+# your users are constantly filling up the disk or exceeding their\r
+# quotas, then you will need to fix this.\r
+\r
+sub doWriteSize {\r
+       my ($line, $proto, $op, $key, $client, $xid, $response, $time) = @_;\r
+\r
+       if ($proto eq 'C3' || $proto eq 'C2') {\r
+\r
+               my $tag = ($proto eq 'C3') ? 'count' : 'tcount';\r
+\r
+               my $count = nfsd::nfsDumpParseLineField ($line, $tag);\r
+\r
+               if (! $count) {\r
+                       printf "WEIRD count $line\n";\r
+               }\r
+\r
+               $count = hex ($count);\r
+\r
+               $counts::OpCounts{"$key,writeM"} += $count;\r
+       }\r
+}\r
+\r
+\r
+# Purge all the pending XID records dated earlier than $when (which is\r
+# typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
+# because otherwise missing XID records can pile up, eating a lot of\r
+# memory. \r
+  \r
+sub prunePending {\r
+       my ($when) = @_;\r
+\r
+       foreach my $uxid ( keys %uxid2time ) {\r
+               if ($uxid2time{$uxid} < $when) {\r
+                       delete $uxid2key{$uxid};\r
+                       delete $uxid2time{$uxid};\r
+               }\r
+       }\r
+\r
+       return ;\r
+}\r
+\r
diff --git a/TBBT/trace_init/nfsscan.txt b/TBBT/trace_init/nfsscan.txt
new file mode 100755 (executable)
index 0000000..b004339
--- /dev/null
@@ -0,0 +1,230 @@
+# Copyright (c) 2002-2003
+#      The President and Fellows of Harvard College.
+#
+# $Id: nfsscan.txt,v 1.5 2003/07/28 14:27:16 ellard Exp $
+
+NFSSCAN DOCUMENTATION
+
+This is version 0.10a of nfsscan, dated 7/25/2003.
+
+THIS IS A PRELIMINARY RELEASE OF A NEW UTILITY.  YOU SHOULD ASSUME
+THAT THE COMMANDLINE FORMATS WILL EVOLVE RAPIDLY OVER THE NEXT SEVERAL
+WEEKS.
+Please report bugs, problems or suggestions for improvements to
+ellard@eecs.harvard.edu.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+COMMANDLINE OPTIONS
+
+Usage: nfsscan [options] [trace1 [trace2 ...]]
+
+If no trace files are specified, then the trace is read from stdin.
+
+Command line options:
+
+-h             Print usage message and exit.
+
+-B [CFUG]      Compute per-Client, per-File, per-User, or per-Group info.
+
+-c c1[,c2]*    Include only activity performed by the specified clients.
+
+-C c1[,c2]*    Exclude activity performed by the specified clients.
+
+-d             Compute per-directory statistics.  This implicitly
+               enables -BF so that per-file info is computed.
+
+-f             Do file info tracking.  This implicitly enables -BF so
+               that per-File info is computed.
+
+-F fhtype      Specify the file handle type used by the server.
+               (advfs or netapp)
+
+-g g1[,g2]*    Include only activity performed by the specified groups.
+
+-G g1[,g2]*    Exclude activity performed by the specified groups.
+
+-l             Record average operation latency.
+
+-o basename    Write output to files starting with the specified
+               basename.  The "Count" table goes to basename.cnt,
+               "Latency" to basename.lat, and "File" to basename.fil.
+               The default is to write all output to stdout.
+
+-O op[,op]*    Specify the list of "interesting" operations.
+               The default list is:
+
+               read,write,lookup,getattr,access,create,remove
+
+               If the first op starts with +, then the specified list
+               of ops is appended to the default list.  The special
+               pseudo-ops readM and writeM represent the number of
+               bytes read and written, expressed in MB.
+
+-t interval    Time interval for cummulative statistics (such as
+               operation count).  The default is 300 seconds. 
+               If set to 0, then the entire trace is processed.  By
+               default, time is specified in seconds, but if the last
+               character of the interval is any of s, m, h, or d,
+               then the interval is interpreted as seconds, minutes,
+               hours, or days.
+
+-u u1[,u2]*    Include only activity performed by the specified users.
+
+-U u1[,u2]*    Exclude activity performed by the specified users.
+
+-Z             Omit count and latency lines that have a zero total
+               operation count.
+
+
+OUTPUT FORMATS
+
+Each line generated by nfsscan begins with a token that indicates the
+table to which it belongs.
+
+COUNT LINES
+
+These lines all begin with 'C' (or #C, for comments),
+and have the following format:
+
+C time client euid egid fh TOTAL INTERESTING <OPS>
+
+time - The time of the start of the measurement interval.
+
+client - The IP number of the client.  If the user has not
+       requested per-client statistics, this field is 'u'.
+
+euid - The effective uid of the caller, in decimal.  If the user has
+       not requested per-user statistics, this field is 'u'.
+
+egid - The effective gid of the caller, in decimal.  If the user has
+       not requested per-group statistics, this field is 'u'.
+
+fh - The file handle used by the operation.  If the user has not
+       requested per-file statistics, this field is 'u'.
+
+TOTAL - The total number of operations for the given client, euid,
+       egid, and fh, for all the operations in <OPS...>.  Note that
+       this is NOT the same as the total of all operations!  For
+       example, if you set <OPS> to the empty list, the TOTAL will
+       always be zero.
+
+INTERESTING - The total number of "interesting" operations.  These are
+       either the default operations (listed below) or the whatever
+       set of operations the user specifies.
+
+
+<OPS> - Following INTERESTING, the count for each "interesting"
+       operation observed during the measurement interval is printed. 
+       The list of operations can be specified or extended on the
+       commandline.  By default, the list of operations is:
+
+               read, write, lookup, getattr, access, create, remove
+
+LATENCY LINES
+
+The format for the "latency" lines is like that of the "count" lines,
+except the lines all begin with "L" (or "#L") and each count
+(including the TOTAL and INTERESTING counts) is followed the average
+latency for that operation.  If the count for a particular operation
+is 0, then the average latency is shown as -1.
+
+Note that the counts for the latency lines may be (and often are)
+different than the counts for count lines.  This is because the count
+lines show the number of calls that were observed, and the latency
+lines require observing both calls and reponses.
+
+FILE LINES
+
+These lines show information about files, rather than information
+about calls.  These lines all begin with "F" (or "#F").  The file
+information (size, mode, etc) are currently only printed for files,
+not directories.
+
+The format is:
+
+F type state fh path dirs mode size atime mtime ctime
+
+type - Either "F" for file, or "D" for directory.
+
+state - "A" if the file is still alive at the end of the
+       trace, or "D" if the file has been deleted.
+
+fh - The file handle.
+
+path - as much of the file path as can be reconstructed from the
+       observed traffic.
+
+dirs - the number of directories in the path.
+
+mode - the most recently observed permissions on the file, in hex.
+
+size - the most recently observed size of the file, in hex.
+
+atime - last access time of the file
+
+mtime - last modification time of the file
+
+ctime - last file status change time
+
+DIRECTORY LINES
+
+These lines show operation count information for files and
+directories.  These lines all begin with "D" (or "#D").  Each line
+begins with the following fields:
+
+time - The time of the start of the measurement interval.
+
+Dir/File - D for directory, F for file.
+
+dircnt - The length of the path to that directory, or zero for files.
+
+path - The path from the mount point to the directory or file.
+
+fh - The file handle of the directory or file.
+
+TOTAL - The total number of operations for the given client, euid,
+       egid, and fh, for all the operations in <OPS...>.  Note that
+       this is NOT the same as the total of all operations!  For
+       example, if you set <OPS> to the empty list, the TOTAL will
+       always be zero.
+
+Following the TOTAL, the count for each "interesting" operation
+observed during the measurement interval is printed.  The list of
+operations can be specified on the commandline.  By default, the list
+of operations is:
+
+       read, write, lookup, getattr, access, create, remove
+
+The information for files is redundant because this information is
+also reflected in the Count lines (if -BF is used), but it is
+sometimes useful to have it in the same format as the directory info.
+
+The TOTAL and op counts for directories represent the total number of
+ops for the files in that directory AND all of its subdirectories.
+
+NOTE: there are several potential problems with the directory information:
+
+       1.  It is possible (and not uncommon) for some part of a path
+               to be missing from the traces.  The path is
+               reconstructed as far back to the root as possible, but
+               this is not always successful.
+
+               If no information about the name of a file is known,
+               then it is given the name ".".
+
+       2.  If files are renamed during the trace, then the name shown
+               is the most recent name for the file.
+
+       3.  If files are removed during the trace, they are still
+               reported in the summary.
+
+               This can lead to an error:  if a directory is deleted,
+               and then another directory is created elsewhere with a
+               new name but the same inode number, this new directory
+               can "inherit" all the info about the files in the old
+               directory, including parentage.  In the worst case,
+               this can cause a loop.  The program will detect such
+               loops, and therefore not get caught forever, but it
+               doesn't do anything clever about them.
diff --git a/TBBT/trace_init/ns_loc2gmt.pl b/TBBT/trace_init/ns_loc2gmt.pl
new file mode 100755 (executable)
index 0000000..815f68f
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/perl\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_loc2gmt,v 1.6 2003/07/28 14:27:16 ellard Exp $\r
+#\r
+# A helper application used by ns_quickview to convert from local time\r
+# to GMT.  nfsdump records time as localtime, but gnuplot only know\r
+# how to deal with dates expressed as Greenwich Mean Time (which it\r
+# then displays using the local time, for some reason).\r
+#\r
+# This is a fragile tool -- it must be run in the same time zone in\r
+# which the data was collected via nfsdump, or else it will not do the\r
+# proper conversion.  Improvements welcomed!\r
+#\r
+# The 'C' (count) and 'L' (latency) records use the second column for\r
+# dates, expressed as seconds.microseconds in localtime.  The seconds\r
+# portion is the only part of the data modified by this program. \r
+# Comment lines are passed through unaltered.\r
+#\r
+# There is no error checking.  Garbage in, garbage out.\r
+#\r
+# Note - we're throwing the microseconds away.\r
+\r
+\r
+use Getopt::Std;\r
+require 'timelocal.pl';\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] [table1.ns [table2.ns ... ]]\r
+\r
+If no table files are specified, then the input is read from stdin.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-d secs                Time offset, in seconds, to subtract from each time\r
+               in the input tables.  Note that all times are rounded\r
+               down to the nearest second.\r
+\r
+IMPORTANT NOTE:  this must be run in the same time zone in which the\r
+data was collected via nfsdump, or else it will not do the proper\r
+conversion unless the -d option is used.\r
+\r
+.\r
+\r
+$Options = "d:";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+       exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+$TimeOffset = 0;\r
+if (defined $opt_d) {\r
+       $TimeOffset = int ($opt_d);\r
+}\r
+\r
+while ($line = <>) {\r
+       if ($line =~ /^#/) {\r
+               print $line;\r
+               next;\r
+       }\r
+\r
+       @arr = split (' ', $line);\r
+\r
+       ($secs, $usec) = split (/\./, $arr[1]);\r
+       $secs -= $TimeOffset;\r
+\r
+       $arr[1] = &timegm (localtime ($secs));\r
+\r
+       print join (' ', @arr);\r
+       print "\n";\r
+}\r
+\r
+exit (0);\r
+\r
diff --git a/TBBT/trace_init/ns_quickview.pl b/TBBT/trace_init/ns_quickview.pl
new file mode 100755 (executable)
index 0000000..1460235
--- /dev/null
@@ -0,0 +1,245 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_quickview,v 1.9 2003/07/28 14:27:17 ellard Exp $\r
+\r
+use Getopt::Std;\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+$GNUPLOT_PATH  = "gnuplot";\r
+$GNUPLOT_OPTS  = "-persist";\r
+$LOC2GMT_PATH  = "$ProgDir/ns_loc2gmt";\r
+\r
+$OUTPUT                = "qv.ps";\r
+$GP_OUTPUT     = "qv.gp";\r
+$TERMINAL      = "postscript";\r
+$SIZE          = undef;\r
+$EXTRA_CMD     = undef;\r
+$TITLE_TEXT    = undef;\r
+$PLOT_OPTS     = '';\r
+@OPS           = ( 7 );\r
+@SCALES                = ();\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] table1.ns [table2.ns ...]\r
+\r
+At least one table file must be specified.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-c cmd         Pass an extra command directly to gnuplot.\r
+\r
+-g             Save the gnuplot commands to $GP_OUTPUT instead\r
+               of executing the immediately.\r
+\r
+-k             Show the key for each line on the plot.  The default\r
+               is not to show the key.\r
+\r
+-l             If more than one input file is specified, superimpose\r
+               the plot for each so that they all appear to begin at\r
+               the same time as the first row in the first file.\r
+\r
+-o filename    Save the plot to the specified file.  The default\r
+               output file is \"$OUTPUT\".\r
+\r
+-O op1,...,opN Plot the specified columns from the table.  The\r
+               default is $OPS[0], the total operation count.\r
+               Note that the operations must be specified by column\r
+               number, not by name.\r
+\r
+-t terminal    Create a plot for the given gnuplot terminal specification.\r
+               The default is \"$TERMINAL\".  See the gnuplot\r
+               documentation for more information.\r
+\r
+-T string      Use the specified string as the title for the plot.\r
+               The default is no title.\r
+\r
+-s sizespec    Set the output size specifier.  See the gnuplot\r
+               documentation for more information.\r
+\r
+-S s1,..,sN    Set the scaling factor for each file.  This is useful\r
+               for plotting files aggregated across different time\r
+               intervals on the same scale.\r
+\r
+.\r
+\r
+$Options = "c:ghklo:O:P:t:T:s:S:";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+       exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+$EXTRA_CMD     = $opt_c        if (defined $opt_c);\r
+$OUTPUT                = $opt_o        if (defined $opt_o);\r
+$TERMINAL      = $opt_t        if (defined $opt_t);\r
+$SIZE          = $opt_s        if (defined $opt_s);\r
+$TITLE_TEXT    = $opt_T        if (defined $opt_T);\r
+$PLOT_OPTS     = $opt_P        if (defined $opt_P);\r
+@OPS   = split (/,/, $opt_O)   if (defined $opt_O);\r
+@SCALES        = split (/,/, $opt_S)   if (defined $opt_S);\r
+\r
+$SAVE_GNUPLOT  = defined $opt_g;\r
+$SHOW_KEY      = defined $opt_k;\r
+$LAYER         = defined $opt_l;\r
+\r
+@FILES = @ARGV;\r
+\r
+if (@FILES == 0) {\r
+       print STDERR "No tables to plot?\n";\r
+       exit (1);\r
+}\r
+\r
+&makePlot;\r
+exit (0);\r
+\r
+sub makePlot {\r
+       my @starts = ();\r
+       my @ends = ();\r
+\r
+       my $nfiles = @FILES;\r
+       my $nops = @OPS;\r
+\r
+       if ($SAVE_GNUPLOT) {\r
+               die unless open (PLOT, ">$GP_OUTPUT");\r
+       }\r
+       else {\r
+               die unless open (PLOT, "|$GNUPLOT_PATH $GNUPLOT_OPTS");\r
+       }\r
+\r
+       $preamble = `cat $ProgDir/template.gp`;\r
+       print PLOT $preamble;\r
+\r
+       print PLOT "set terminal $TERMINAL\n";\r
+       print PLOT "set output \'$OUTPUT\'\n";\r
+       if (defined $SIZE) {\r
+               print PLOT "set size $SIZE\n";\r
+       }\r
+\r
+       if (defined $TITLE_TEXT) {\r
+               print PLOT "set title \"$TITLE_TEXT\"\n";\r
+       }\r
+\r
+       if (defined $EXTRA_CMD) {\r
+               print PLOT "$EXTRA_CMD\n";\r
+       }\r
+\r
+       print PLOT "set key below\n";\r
+\r
+       if ($LAYER) {\r
+               for ($i = 0; $i < $nfiles; $i++) {\r
+                       ($starts [$i], $ends [$i]) =\r
+                                       findFileTimeSpan ($FILES [$i]);\r
+               }\r
+       }\r
+\r
+       print PLOT "plot $PLOT_OPTS \\\n";\r
+       for ($i = 0; $i < $nfiles; $i++) {\r
+               my $offset = 0;\r
+               my $scale = 1;\r
+               if (defined $SCALES[$i]) {\r
+                       $scale = $SCALES[$i];\r
+               }\r
+\r
+               my $file = $FILES [$i];\r
+\r
+               if ($LAYER) {\r
+                       $offset = $starts [$i] - $starts [0];\r
+               }\r
+\r
+               for ($j = 0; $j < @OPS; $j++) {\r
+                       my $op = $OPS[$j];\r
+\r
+                       print PLOT "\t\"< $LOC2GMT_PATH -d $offset $file\" \\\n";\r
+                       print PLOT "\t\tusing 2:(\$$op*$scale) \\\n";\r
+                       if ($SHOW_KEY) {\r
+                               print PLOT "\t\ttitle \'$file:$op\'\\\n";\r
+                       }\r
+                       print PLOT "\t\twith lines lw 2";\r
+                       if ($i != $nfiles - 1 || $j != $nops - 1) {\r
+                               print PLOT ",\\\n";\r
+                       }\r
+                       else {\r
+                               print PLOT "\n";\r
+                       }\r
+               }\r
+       }\r
+       print PLOT "\n";\r
+       close PLOT;\r
+}\r
+\r
+# Find the earliest and latest times in a file created by nfsscan, and\r
+# return them as a list.  Returns the empty list if anything goes\r
+# wrong.\r
+\r
+sub findFileTimeSpan {\r
+       my ($fname) = @_;\r
+       my ($smallest, $largest) = (-1, -1);\r
+\r
+       if (! open (FF, "<$fname")) {\r
+               return ();\r
+       }\r
+\r
+       while (my $l = <FF>) {\r
+               if ($l =~ /^#/) {\r
+                       next;\r
+               }\r
+\r
+               @a = split (' ', $l);\r
+\r
+               if ($smallest < 0 || $smallest > $a[1]) {\r
+                       $smallest = $a[1];\r
+               }\r
+               if ($largest < 0 || $largest < $a[1]) {\r
+                       $largest = $a[1];\r
+               }\r
+       }\r
+\r
+       close FF;\r
+\r
+       if ((! defined $smallest) || (! defined $largest)) {\r
+               return ();\r
+       }\r
+\r
+       return ($smallest, $largest);\r
+}\r
+\r
diff --git a/TBBT/trace_init/ns_split.pl b/TBBT/trace_init/ns_split.pl
new file mode 100755 (executable)
index 0000000..b600448
--- /dev/null
@@ -0,0 +1,153 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_split,v 1.4 2003/07/28 14:27:17 ellard Exp $\r
+\r
+use Getopt::Std;\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+require "$ProgDir/userUtils.pl";\r
+\r
+@ADD_USERS     = ();\r
+@DEL_USERS     = ();\r
+@ADD_GROUPS    = ();\r
+@DEL_GROUPS    = ();\r
+@ADD_CLIENTS   = ();\r
+@DEL_CLIENTS   = ();\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] [table1.ns [table2.ns ... ]]\r
+\r
+If no table files are specified, then the input is read from stdin.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-c c1[,c2]*    Include only activity performed by the specified clients.\r
+\r
+-C c1[,c2]*    Exclude activity performed by the specified clients.\r
+\r
+-g g1[,g2]*    Include only activity performed by the specified groups.\r
+\r
+-G g1[,g2]*    Exclude activity performed by the specified groups.\r
+\r
+-u u1[,u2]*    Include only activity performed by the specified users.\r
+\r
+-U u1[,u2]*    Exclude activity performed by the specified users.\r
+\r
+.\r
+\r
+$cmdline = "$0 " . join (' ', @ARGV);\r
+$Options = "c:C:g:G:u:U::";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+if (defined $opt_u) {\r
+       @ADD_USERS = &logins2uids ($opt_u);\r
+}\r
+if (defined $opt_U) {\r
+       @DEL_USERS = &logins2uids ($opt_U);\r
+}\r
+if (defined $opt_g) {\r
+       @ADD_GROUPS = &groups2gids ($opt_g);\r
+}\r
+if (defined $opt_G) {\r
+       @DEL_GROUPS = &groups2gids ($opt_G);\r
+}\r
+if (defined $opt_c) {\r
+       @ADD_CLIENTS = split (/,/, $opt_c);\r
+}\r
+if (defined $opt_C) {\r
+       @DEL_CLIENTS = split (/,/, $opt_C);\r
+}\r
+\r
+print "#cmdline $cmdline\n";\r
+\r
+while ($l = <>) {\r
+       if ($l =~ /^#/) {\r
+               print $l;\r
+               next;\r
+       }\r
+\r
+       my ($type, $time, $client, $fh, $euid, $egid, @vals) = split (' ', $l);\r
+\r
+       next unless ($type eq 'C');\r
+\r
+       # Something wrong with the input?\r
+\r
+       next if (@vals == 0);\r
+\r
+       if (saveRecord ($client, $fh, $euid, $egid)) {\r
+               print $l;\r
+       }\r
+}\r
+\r
+sub saveRecord {\r
+       my ($client, $fh, $euid, $egid) = @_;\r
+\r
+       if (@ADD_CLIENTS && !grep (/^$client$/, @ADD_CLIENTS)) {\r
+               return 0;\r
+       }\r
+       if (@DEL_CLIENTS && grep (/^$client$/, @DEL_CLIENTS)) {\r
+               return 0;\r
+       }\r
+\r
+       if (@ADD_USERS && !grep (/^$euid$/, @ADD_USERS)) {\r
+               return 0;\r
+       }\r
+       if (@DEL_USERS && grep (/^$euid$/, @DEL_USERS)) {\r
+               return 0;\r
+       }\r
+\r
+       if (@ADD_GROUPS && !grep (/^$egid$/, @ADD_GROUPS)) {\r
+               return 0;\r
+       }\r
+       if (@DEL_GROUPS && grep (/^$egid$/, @DEL_GROUPS)) {\r
+               return 0;\r
+       }\r
+\r
+       return (1);\r
+}\r
+\r
+exit 0;\r
diff --git a/TBBT/trace_init/ns_timeagg.pl b/TBBT/trace_init/ns_timeagg.pl
new file mode 100755 (executable)
index 0000000..9e5e536
--- /dev/null
@@ -0,0 +1,218 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_timeagg,v 1.7 2003/07/28 14:27:17 ellard Exp $\r
+\r
+use Getopt::Std;\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+require "$ProgDir/common.pl";\r
+\r
+$UseClient     = 0;\r
+$UseFH         = 0;\r
+$UseUID                = 0;\r
+$UseGID                = 0;\r
+$NEW_INTERVAL  = 300;\r
+$OMIT_ZEROS    = 0;\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] [table1.ns [table2.ns ... ]]\r
+\r
+If no table files are specified, then the input is read from stdin.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-B flags       Choose fields to NOT aggregate.  The fields are:\r
+               C - client host ID\r
+               U - Effective user ID\r
+               G - Effective group ID\r
+               F - File handle\r
+\r
+-R secs                Round the start time to the closest multiple of\r
+               the given number of seconds.  This is useful for\r
+               dealing with small amounts of clock drift.  For example,\r
+               if the trace starts at 12:00:01 instead of 12:00:00,\r
+               it is probably convenient to pretend that it started\r
+               at 12:00:00.\r
+\r
+-t secs                Aggregate over the given number of seconds.   The default\r
+               is $NEW_INTERVAL.  If the current interval does not\r
+               divide the new interval, warning messages are printed\r
+               and the output might not be meaningful.\r
+\r
+               If secs is 0, then the total for the entire table is\r
+               computed.\r
+\r
+-Z             Omit count lines that have a zero total operation count.\r
+.\r
+\r
+$cmdline = "$0 " . join (' ', @ARGV);\r
+$Options = "B:hR:t:Z";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+       exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+if (defined $opt_t) {\r
+       if ($opt_t <= 0) {\r
+               $EndTime = 0;\r
+       }\r
+       $NEW_INTERVAL   = $opt_t;\r
+}\r
+\r
+$TIME_ROUNDING = defined $opt_R ? $opt_R : 0;\r
+\r
+if (defined $opt_B) {\r
+       $UseClient = ($opt_B =~ /C/);\r
+       $UseUID = ($opt_B =~ /U/);\r
+       $UseGID  = ($opt_B =~ /G/);\r
+       $UseFH = ($opt_B =~ /F/);\r
+}\r
+\r
+# We need to let the measurement of time be a little bit inexact, so\r
+# that a small rounding error or truncation doesn't throw everything\r
+# off.\r
+\r
+$TimerInacc = 0.05;\r
+\r
+# Print out the commandline as a comment in the output.\r
+\r
+print "#cmdline $cmdline\n";\r
+\r
+# It would be nice to make this do the right thing with Latency lines,\r
+# and perhaps file op counts.\r
+\r
+while ($l = <>) {\r
+       if ($l =~ /^#C/) {\r
+               print $l;\r
+               next;\r
+       }\r
+\r
+       next if ($l =~ /^#/);\r
+\r
+       my ($type, $time, $client, $fh, $euid, $egid, @vals) = split (' ', $l);\r
+\r
+       next unless ($type eq 'C');\r
+\r
+       # Something wrong with the input?\r
+\r
+       next if (@vals == 0);\r
+\r
+       if (!defined $StartTime) {\r
+               $StartTime = findStartTime ($time, $TIME_ROUNDING);\r
+               if ($NEW_INTERVAL > 0) {\r
+                       $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
+               }\r
+       }\r
+\r
+       if ($EndTime > 0 && $time >= $EndTime) {\r
+               my $diff = int ($time - $StartTime);\r
+               if ($diff > 0) {\r
+                       if ($NEW_INTERVAL % $diff != 0) {\r
+                               print STDERR "$0: time interval mismatch ";\r
+                               print STDERR "(from $diff to $NEW_INTERVAL)\n";\r
+                       }\r
+               }\r
+\r
+               dumpKeys ($StartTime);\r
+\r
+               $StartTime += $NEW_INTERVAL;\r
+               $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
+       }\r
+\r
+\r
+       # Aggregate across clients, files, users, and groups unless\r
+       # specifically asked NOT to.\r
+\r
+       $client = $UseClient ? $client : 'u';\r
+       $fh = $UseFH ? $fh : 'u';\r
+       $euid = $UseUID ? $euid : 'u';\r
+       $egid = $UseGID  ? $egid : 'u';\r
+\r
+       $key = "$client,$fh,$euid,$egid";\r
+\r
+       if (exists $Totals{$key}) {\r
+               my (@tots) = split (' ', $Totals{$key});\r
+               for (my $i = 0; $i < @vals; $i++) {\r
+                       $tots[$i] += $vals[$i];\r
+               }\r
+               $Totals{$key} = join (' ', @tots);\r
+       }\r
+       else {\r
+               $Totals{$key} = join (' ', @vals);\r
+       }\r
+}\r
+\r
+if ($EndTime <= 0) {\r
+       dumpKeys ($StartTime);\r
+}\r
+\r
+sub dumpKeys {\r
+       my ($start) = @_;\r
+       my ($i, $k, $ks);\r
+\r
+       foreach $k ( keys %Totals ) {\r
+               my (@v) = split (' ', $Totals{$k});\r
+\r
+               if ($OMIT_ZEROS && $v[0] == 0) {\r
+                       next;\r
+               }\r
+\r
+               $ks = $k;\r
+               $ks =~ s/,/\ /g;\r
+\r
+               print "C $start $ks";\r
+\r
+               for ($i = 0; $i < @v; $i++) {\r
+                       print " $v[$i]";\r
+               }\r
+               print "\n";\r
+\r
+               for ($i = 0; $i < @v; $i++) {\r
+                       $v[$i] = 0;\r
+               }\r
+               $Totals{$k} = join (' ', @v);\r
+       }\r
+}\r
+\r
+exit 0;\r
diff --git a/TBBT/trace_init/ns_tsplit.pl b/TBBT/trace_init/ns_tsplit.pl
new file mode 100755 (executable)
index 0000000..e3dd420
--- /dev/null
@@ -0,0 +1,219 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_tsplit,v 1.4 2003/07/26 20:52:04 ellard Exp $\r
+\r
+use Getopt::Std;\r
+use Time::Local;\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+# Set the default start and end times.\r
+\r
+$DEF_BEGIN_TIME        = "20000101:00:00:00";\r
+$DEF_END_TIME  = "20360101:00:00:00";\r
+\r
+# The range includes everything from the start time up to and less\r
+# than the end time (so if you want one day, it is correct to go\r
+# midnight to midnight, instead of going until 23:59:59).\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] rangeSpec... - [table.ns [table.ns...]]\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+Any number of time range specifier can be provided.  The special\r
+symbol "-" is used to separated the time specifiers from the input\r
+file names.  If input is taken from stdin, then the "-" may be\r
+omitted.\r
+\r
+The basic time range specification format is:  StartTime-EndTime where\r
+StartTime and EndTime have the form YYMMDD[:HH[:MM[:SS]]].  All\r
+records from the input that have a timestamp greater than or equal to\r
+StartTime and less than EndTime are printed to stdout.\r
+\r
+If StartTime is omitted, $DEF_BEGIN_TIME is used.\r
+If EndTime is omitted, $DEF_END_TIME is used.\r
+\r
+Note that omitting both the StartTime and EndTime results in a rangeSpec\r
+of "-", which is the special symbol that marks the end of the rangeSpecs.\r
+.\r
+\r
+$cmdline = "$0 " . join (' ', @ARGV);\r
+$Options = "h";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+       exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+@StartTimes    = ();\r
+@EndTimes      = ();\r
+\r
+while ($ts = shift @ARGV) {\r
+       last if ($ts eq '-');\r
+\r
+       my ($ts_s, $ts_e) = split (/-/, $ts);\r
+       my $s;\r
+\r
+       if ($ts_s eq '') {\r
+               $ts_s = $DEF_START_TIME;\r
+       }\r
+       $s = &ts2secs ($ts_s);\r
+       if (! defined $s) {\r
+               print STDERR "Failed to translate ($ts_s)\n";\r
+               exit (1);\r
+       }\r
+       push @StartTimes, $s;\r
+\r
+       if ($ts_e eq '') {\r
+               $ts_e = $DEF_END_TIME;\r
+       }\r
+       $s = &ts2secs ($ts_e);\r
+       if (! defined $s) {\r
+               print STDERR "Failed to translate ($ts_e)\n";\r
+               exit (1);\r
+       }\r
+\r
+       push @EndTimes, $s;\r
+}\r
+\r
+print "#cmdline $cmdline\n";\r
+\r
+while ($l = <>) {\r
+       if ($l =~ /^#/) {\r
+               print $l;\r
+               next;\r
+       }\r
+\r
+       my ($type, $time, $client, $fh, $euid, $egid, @vals) = split (' ', $l);\r
+\r
+       next unless ($type eq 'C');\r
+\r
+       # Something wrong with the input?\r
+\r
+       next if (@vals == 0);\r
+\r
+       if (saveRecord ($time)) {\r
+               print $l;\r
+       }\r
+}\r
+\r
+exit 0;\r
+\r
+sub saveRecord {\r
+       my ($t) = @_;\r
+\r
+       for (my $i = 0; $i < @StartTimes ; $i++) {\r
+               if (($StartTimes[$i] <= $t) && ($t < $EndTimes[$i])) {\r
+                       return (1);\r
+               }\r
+       }\r
+\r
+       return (0);\r
+}\r
+\r
+# This is ugly!\r
+#\r
+# The basic time specification format is:  YYMMDD[:HH[:MM[:SS]]].\r
+#\r
+# To make a time range, join two time specs with a -.\r
+#\r
+# The data spec is Y2.01K compliant...  I'm assuming that all the\r
+# traces processed by this tool will be gathered before 2010.  If\r
+# anyone is still gathering NFSv3 traces in 2010, I'm sorry.\r
+\r
+sub ts2secs {\r
+       my ($ts) = @_;\r
+       my ($hour, $min, $sec) = (0, 0, 0);\r
+\r
+       my (@d) = split (/:/, $ts);\r
+\r
+       if ($d[0] =~ /([0-9][0-9])([0-2][0-9])([0-3][0-9])/) {\r
+               $year = $1 + 100;\r
+               $mon = $2 - 1;\r
+               $day = $3;\r
+       }\r
+       else {\r
+               return undef;\r
+       }\r
+\r
+       if (@d > 1) {\r
+               if ($d[1] =~ /([0-2][0-9])/) {\r
+                       $hour = $1;\r
+               }\r
+               else {\r
+                       return undef;\r
+               }\r
+       }\r
+\r
+       if (@d > 2) {\r
+               if ($d[2] =~ /([0-5][0-9])/) {\r
+                       $min = $1;\r
+               }\r
+               else {\r
+                       return undef;\r
+               }\r
+       }\r
+\r
+       if (@d > 3) {\r
+               if ($d[3] =~ /([0-5][0-9])/) {\r
+                       $sec = $1;\r
+               }\r
+               else {\r
+                       return undef;\r
+               }\r
+       }\r
+\r
+       my $s = timelocal ($sec, $min, $hour, $day, $mon, $year,\r
+                       undef, undef, undef);\r
+\r
+       my ($s2, $m2, $h2, $md2, $mon2, $y2, $isdst) = localtime ($s);\r
+       if (($s2 != $sec) || $min != $m2 || $hour != $h2 || $day != $md2) {\r
+               print "failed 1!\n";\r
+       }\r
+       if (($mon != $mon2) || $year != $y2) {\r
+               print "failed 2!\n";\r
+       }\r
+\r
+       return ($s);\r
+}\r
+\r
diff --git a/TBBT/trace_init/rfs.pl b/TBBT/trace_init/rfs.pl
new file mode 100755 (executable)
index 0000000..c167df7
--- /dev/null
@@ -0,0 +1,243 @@
+#!/usr/bin/perl -w\r
+\r
+use Getopt::Std;\r
+$Usage =<< "EOF";\r
+\r
+Usage: $0 [options]\r
+\r
+This program runs after nfsscan.pl. It outputs the file system hierarchy (RFSFS) as well as\r
+the file system hierarchy map (stored in three files: fh-path-map, noattrdirdiscard, noattrdir-root).\r
+\r
+This perl program do post processing based on this file\r
+\r
+Command line options:\r
+\r
+-h     Print Usage message and exit.\r
+\r
+-S  The file in file system hierarchy are all of size 0. \r
+    Without -S, the files are written to it full length.\r
+\r
+\r
+EOF\r
+\r
+$writebuf = "R" x 8193;\r
+$writeBlockSize = 8192;\r
+\r
+main ();\r
+\r
+sub rfsCreateSymlink()\r
+{\r
+        my ($path, $pathcnt, $sizeHexStr) = @_;\r
+        $sizeHexStr = "0x".$sizeHexStr;\r
+\r
+        my $dir = $path;\r
+        my $name = '';\r
+        my $cmdbuf;\r
+\r
+        $dir =~ /(^.*)\/(.*)/;\r
+        $dir = $1;\r
+        $name = $2;\r
+        if (!$dir) {$dir = ".";}\r
+        die "name is empty\n" if (!$name);\r
+        #print "path($path) dir($dir) name($name)\n";\r
+\r
+        if (! -e $dir) {\r
+                $cmdbuf = "mkdir -p $dir";\r
+                system $cmdbuf;\r
+                print "RFS: Warning: the directory should be created already: $path\n";\r
+        } else {\r
+                die "warning: directory name exist but not a directory: $path\n" if (!(-d $dir));\r
+        }\r
+\r
+        my $size = hex($sizeHexStr);\r
+        #print "size($sizeHexStr) lp($lp) rem($remSize)\n";\r
+\r
+        my $pathnamebuf = $sizeHexStr;\r
+        symlink ($pathnamebuf, $path);\r
+        #if (! symlink ($pathnamebuf, $path) ) {\r
+        #      print STDERR "JIAWU: WARNING: failed to create symlink: $path -> $pathnamebuf\n";\r
+        #}\r
+}\r
+\r
+\r
+sub  rfsCreateFile()\r
+{\r
+        my ($path, $pathcnt, $sizeHexStr) = @_;\r
+        $sizeHexStr = "0x".$sizeHexStr;\r
+\r
+        my $dir = $path;\r
+        my $name = '';\r
+        my $cmdbuf;\r
+\r
+        $dir =~ /(^.*)\/(.*)/;\r
+        $dir = $1;\r
+        $name = $2;\r
+        if (!$dir) {$dir = ".";}\r
+        die "name is empty\n" if (!$name);\r
+        #print "path($path) dir($dir) name($name)\n";\r
+\r
+        if (! -e $dir) {\r
+                $cmdbuf = "mkdir -p $dir";\r
+                system $cmdbuf;\r
+                print "RFS: Warning: the directory should be created already: $path\n";\r
+        } else {\r
+                die "warning: directory name exist but not a directory: $path\n" if (!(-d $dir));\r
+        }\r
+\r
+        my $size = hex($sizeHexStr);\r
+        my $remSize = $size % $writeBlockSize;\r
+        my $lp = ($size - $remSize) / $writeBlockSize;\r
+        #print "size($sizeHexStr) lp($lp) rem($remSize)\n";\r
+\r
+        open RFSTMPWRITE, ">$path" || die "RFS: can not open file for write";\r
+\r
+       # the eight lines below should not be commented out \r
+               if (!defined $opt_S) {\r
+        my $i = 0;\r
+        for ($i = 0; $i < $lp; $i++) {\r
+                syswrite(RFSTMPWRITE, $writebuf, $writeBlockSize);\r
+        }\r
+        if ($remSize) {\r
+                syswrite(RFSTMPWRITE, $writebuf, $remSize);\r
+                #print "write ($remSize) byte\n";\r
+        }\r
+        close RFSTMPWRITE;\r
+               }\r
+}\r
+\r
+# Useful commands:\r
+# sort -n -k a,b -c -u \r
+# \r
+# *** WARNING *** The locale specified by the  environment  affects  sort\r
+#      order.  Set LC_ALL=C or LC_ALL=POSIX to get the traditional sort order that uses native\r
+#      byte values.\r
+\r
+sub parseArgs {\r
+       my $Options = "S";\r
+       if (! getopts($Options)) {\r
+               print STDERR "$0: Incorrect usage.\n";\r
+        print STDERR $Usage;\r
+               exit (1);\r
+       }\r
+}\r
+\r
+sub main {\r
+\r
+       parseArgs ();\r
+\r
+       my $cmdbuf;\r
+\r
+       # format of lines in test.fil:\r
+       # "F(1) $type(2) $state(3) $fh(4) $path(5) $pathcnt(6) $attrOrig(7-14) $attr()\r
+       # attrOrig: ($size(7) $mode(8) $op(9) $atime(10) $mtime(11) $ctime(12) $nlink(13) $ts(14))\r
+       # attrLast: ($size(15) $mode(16) $op(17) $atime(18) $mtime(19) $ctime(20) $nlink(21) $ts(22))\r
+\r
+       # skip comment lines\r
+       # if (path_count ($6) == 0 or original_op($9) == "create" or "mkdir" or "symlink") skip the file \r
+\r
+       $cmdbuf = 'gawk \' !/^[#]/ { if ($6 != "0") print $0 }\'  test.fil > all.fil';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # sort the test.fil according to path name\r
+       $cmdbuf = 'export LC_ALL=C; sort -k 5,5 all.fil > all.fil.order; echo $LC_ALL';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # keep the interested field only\r
+       # 2(D/F) 4(FH) 5(path) 6(count) 15(size_last) 21(nlink_last) 14(ts_s) 22(ts_e)\r
+       $cmdbuf = 'gawk \' { print $14, $22, $4, $5, $15, $21}\'  all.fil.order > fh-path-map-all';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # skip comment lines\r
+       # if (path_count ($6) == 0 or original_op($9) == "create" or "mkdir" or "symlink") skip the file \r
+\r
+       $cmdbuf = 'gawk \' !/^[#]/ { if ($6 != "0" && $9 != "create" && $9 != "mkdir" && $9 != "symlink") print $0 }\'  test.fil > active.fil';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # sort the active.fil according to path name\r
+       $cmdbuf = 'export LC_ALL=C; sort -k 5,5 active.fil > active.fil.order; echo $LC_ALL';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # keep the interested field only\r
+       # 2(D/F) 4(FH) 5(path) 6(count) 7(size) 8(mode) 13(nlink)\r
+       $cmdbuf = 'gawk \' { print $2, $4, $5, $6, $7, $8 }\'  active.fil.order > active';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'gawk \' { print $4, $5, $7, $13}\'  active.fil.order > fh-path-map';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # format output files\r
+       $cmdbuf = 'export LC_ALL=C; mv noattrdirdiscard noattrdirdiscard-tmp; sort -u -k 1,1 noattrdirdiscard-tmp > noattrdirdiscard; echo $LC_ALL; rm -f noattrdirdiscard-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       $cmdbuf = 'export LC_ALL=C; mv noattrdir-root noattrdir-root-tmp; sort -u -k 1,1 noattrdir-root-tmp > noattrdir-root; echo $LC_ALL; rm -f noattrdir-root-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       #$cmdbuf = 'mv noattrdirdiscard noattrdirdiscard-tmp; cat  noattrdirdiscard-tmp missdiscardfh >noattrdirdiscard; rm -f noattrdirdiscard-tmp missdiscardfh';\r
+       $cmdbuf = 'mv noattrdirdiscard noattrdirdiscard-tmp; cat  noattrdirdiscard-tmp missdiscardfh >noattrdirdiscard; rm -f noattrdirdiscard-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       $cmdbuf = "cut -d ' ' -f '1 2' fh-path-map > fh-path-map-tmp";\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       $cmdbuf = 'cat noattrdirdiscard noattrdir-root fh-path-map-tmp > fh-path-map-play; rm -rf fh-path-map-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       #exit(0);\r
+       \r
+       # so far, you got the following information\r
+       # in active: all files/dirs active \r
+       # in noattrdir-root: a set of fhs pointing to RFSNN0\r
+       # in rfsinfo: a set of dir fhs refer to RFSNNxxx(>0)\r
+       #                a set of file fhs should be discard due to short of information\r
+\r
+       # create the active fs\r
+       # 1. BASEDIR/RFSNN0\r
+       # 2. BASEDIR/active\r
+       $cmdbuf = "mkdir -p RFSFS/RFSNN0";\r
+       system $cmdbuf;\r
+       open RFS_ACTIVE, "active" || die "open active failed\n";\r
+       while (<RFS_ACTIVE>) {\r
+               chop;\r
+               my ($type, $fh, $path, $pathcnt, $sizeHexStr, $mode) = split (' ', $_, 7);\r
+               if ($type==2) {\r
+                       $cmdbuf = "mkdir -p RFSFS$path";\r
+                       system $cmdbuf;\r
+               }elsif ($type==1){\r
+                       &rfsCreateFile("RFSFS$path", $pathcnt, $sizeHexStr);\r
+               }elsif ($type==5){\r
+                       #print STDERR "SYMLINK: $type fh: $fh path: $path\n";\r
+                       &rfsCreateSymlink("RFSFS$path", $pathcnt, $sizeHexStr);\r
+               }else {\r
+                       print STDERR "special file: $type fh: $fh path: $path\n";\r
+               }\r
+\r
+               my $line_num=0;\r
+               $line_num++;\r
+               if ( ($line_num %100)==0 ) {\r
+                       print STDERR "$line_num\n";\r
+               }\r
+               \r
+       }\r
+\r
+       # create map table: key (fh), value (path/fn)\r
+\r
+       # check whether there is fh that is not mapped to any path/fn in the trace\r
+\r
+       # simulate a replay of trace\r
+\r
+       return;\r
+       \r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/rfs.pl.old b/TBBT/trace_init/rfs.pl.old
new file mode 100755 (executable)
index 0000000..550f2c8
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/perl -w\r
+\r
+$Usage =<< ".";\r
+\r
+This is the rfs program\r
+\r
+After run nfsscan, you will get a file-list file in the output\r
+\r
+This perl program do post processing based on this file\r
+\r
+\r
+.\r
+\r
+$writebuf = "R" x 8193;\r
+$writeBlockSize = 8192;\r
+\r
+\r
+main ();\r
+\r
+sub  rfsCreateFile()\r
+{\r
+        my ($path, $pathcnt, $sizeHexStr) = @_;\r
+        $sizeHexStr = "0x".$sizeHexStr;\r
+\r
+        my $dir = $path;\r
+        my $name = '';\r
+        my $cmdbuf;\r
+\r
+        $dir =~ /(^.*)\/(.*)/;\r
+        $dir = $1;\r
+        $name = $2;\r
+        if (!$dir) {$dir = ".";}\r
+        die "name is empty\n" if (!$name);\r
+        #print "path($path) dir($dir) name($name)\n";\r
+\r
+        if (! -e $dir) {\r
+                $cmdbuf = "mkdir -p $dir";\r
+                system $cmdbuf;\r
+                print "RFS: Warning: the directory should be created already: $path\n";\r
+        } else {\r
+                die "warning: directory name exist but not a directory: $path\n" if (!(-d $dir));\r
+        }\r
+\r
+        my $size = hex($sizeHexStr);\r
+        my $remSize = $size % $writeBlockSize;\r
+        my $lp = ($size - $remSize) / $writeBlockSize;\r
+        #print "size($sizeHexStr) lp($lp) rem($remSize)\n";\r
+\r
+        open RFSTMPWRITE, ">$path" || die "RFS: can not open file for write";\r
+\r
+        my $i = 0;\r
+        for ($i = 0; $i < $lp; $i++) {\r
+                syswrite(RFSTMPWRITE, $writebuf, $writeBlockSize);\r
+        }\r
+        if ($remSize) {\r
+                syswrite(RFSTMPWRITE, $writebuf, $remSize);\r
+                #print "write ($remSize) byte\n";\r
+        }\r
+        close RFSTMPWRITE;\r
+}\r
+\r
+# Useful commands:\r
+# sort -n -k a,b -c -u \r
+# \r
+#\r
+\r
+sub main {\r
+\r
+       my $cmdbuf;\r
+       \r
+       # skip comment lines\r
+       # if (path_count ($6) == 0 or original_op($9) == "create" or "mkdir") skip the file \r
+\r
+       $cmdbuf = 'gawk \' !/^[#]/ { if ($6 != "0" && $9 != "create" && $9 != "mkdir") print $0 }\'  test.fil > active.fil';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # sort the active.fil according to path_count\r
+       $cmdbuf = 'sort -k 5,5 active.fil > active.fil.order';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'sort -n -k 6,6 active.fil > active.fil.order-pathcnt';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # keep the interested field only\r
+       # 2(D/F) 4(FH) 5(path) 6(count) 7(size) 8(mode)\r
+       $cmdbuf = 'gawk \' { print $2, $4, $5, $6, $7, $8 }\'  active.fil.order > active';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'gawk \' { print $4, $5 }\'  active.fil.order > fh-path-map';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'gawk \' { print $2, $4, $5, $6, $7, $8 }\'  active.fil.order-pathcnt > active-pathcnt';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'gawk \' { print $4, $5 }\'  active.fil.order-pathcnt > fh-path-map-pathcnt';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       #exit(0);\r
+       \r
+       # so far, you got the following information\r
+       # in active: all files/dirs active \r
+       # in noattrdir-root: a set of fhs pointing to RFSNN0\r
+       # in rfsinfo: a set of dir fhs refer to RFSNNxxx(>0)\r
+       #                a set of file fhs should be discard due to short of information\r
+\r
+       # create the active fs\r
+       # 1. BASEDIR/RFSNN0\r
+       # 2. BASEDIR/active\r
+       $cmdbuf = "mkdir -p RFSFS/RFSNN0";\r
+       system $cmdbuf;\r
+       open RFS_ACTIVE, "active";\r
+       while (<RFS_ACTIVE>) {\r
+               chop;\r
+               my ($type, $fh, $path, $pathcnt, $sizeHexStr, $mode) = split (' ', $_, 7);\r
+               if ($type eq "D") {\r
+                       $cmdbuf = "mkdir -p RFSFS$path";\r
+                       system $cmdbuf;\r
+               }\r
+               else {\r
+                       &rfsCreateFile("RFSFS$path", $pathcnt, $sizeHexStr);\r
+               }\r
+               \r
+       }\r
+\r
+       # create map table: key (fh), value (path/fn)\r
+\r
+       # check whether there is fh that is not mapped to any path/fn in the trace\r
+\r
+       # simulate a replay of trace\r
+\r
+       return;\r
+       \r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/rfs.stub.pl b/TBBT/trace_init/rfs.stub.pl
new file mode 100755 (executable)
index 0000000..a0de62a
--- /dev/null
@@ -0,0 +1,213 @@
+#!/usr/bin/perl -w\r
+\r
+$Usage =<< ".";\r
+\r
+This is the rfs program\r
+\r
+After run nfsscan, you will get a file-list file in the output\r
+\r
+This perl program do post processing based on this file\r
+\r
+\r
+.\r
+\r
+$writebuf = "R" x 8193;\r
+$writeBlockSize = 8192;\r
+\r
+main ();\r
+\r
+sub rfsCreateSymlink()\r
+{\r
+        my ($path, $pathcnt, $sizeHexStr) = @_;\r
+        $sizeHexStr = "0x".$sizeHexStr;\r
+\r
+        my $dir = $path;\r
+        my $name = '';\r
+        my $cmdbuf;\r
+\r
+        $dir =~ /(^.*)\/(.*)/;\r
+        $dir = $1;\r
+        $name = $2;\r
+        if (!$dir) {$dir = ".";}\r
+        die "name is empty\n" if (!$name);\r
+        #print "path($path) dir($dir) name($name)\n";\r
+\r
+        if (! -e $dir) {\r
+                $cmdbuf = "mkdir -p $dir";\r
+                system $cmdbuf;\r
+                print "RFS: Warning: the directory should be created already: $path\n";\r
+        } else {\r
+                die "warning: directory name exist but not a directory: $path\n" if (!(-d $dir));\r
+        }\r
+\r
+        my $size = hex($sizeHexStr);\r
+        #print "size($sizeHexStr) lp($lp) rem($remSize)\n";\r
+\r
+        my $pathnamebuf = $sizeHexStr;\r
+        symlink ($pathnamebuf, $path);\r
+        #if (! symlink ($pathnamebuf, $path) ) {\r
+        #      print STDERR "JIAWU: WARNING: failed to create symlink: $path -> $pathnamebuf\n";\r
+        #}\r
+}\r
+\r
+\r
+sub  rfsCreateFile()\r
+{\r
+        my ($path, $pathcnt, $sizeHexStr) = @_;\r
+        $sizeHexStr = "0x".$sizeHexStr;\r
+\r
+        my $dir = $path;\r
+        my $name = '';\r
+        my $cmdbuf;\r
+\r
+        $dir =~ /(^.*)\/(.*)/;\r
+        $dir = $1;\r
+        $name = $2;\r
+        if (!$dir) {$dir = ".";}\r
+        die "name is empty\n" if (!$name);\r
+        #print "path($path) dir($dir) name($name)\n";\r
+\r
+        if (! -e $dir) {\r
+                $cmdbuf = "mkdir -p $dir";\r
+                system $cmdbuf;\r
+                print "RFS: Warning: the directory should be created already: $path\n";\r
+        } else {\r
+                die "warning: directory name exist but not a directory: $path\n" if (!(-d $dir));\r
+        }\r
+\r
+        my $size = hex($sizeHexStr);\r
+        my $remSize = $size % $writeBlockSize;\r
+        my $lp = ($size - $remSize) / $writeBlockSize;\r
+        #print "size($sizeHexStr) lp($lp) rem($remSize)\n";\r
+\r
+        open RFSTMPWRITE, ">$path" || die "RFS: can not open file for write";\r
+\r
+       # the eight lines below should not be commented out \r
+        #my $i = 0;\r
+        #for ($i = 0; $i < $lp; $i++) {\r
+        #        syswrite(RFSTMPWRITE, $writebuf, $writeBlockSize);\r
+        #}\r
+        #if ($remSize) {\r
+        #        syswrite(RFSTMPWRITE, $writebuf, $remSize);\r
+        #        #print "write ($remSize) byte\n";\r
+        #}\r
+        close RFSTMPWRITE;\r
+}\r
+\r
+# Useful commands:\r
+# sort -n -k a,b -c -u \r
+# \r
+# *** WARNING *** The locale specified by the  environment  affects  sort\r
+#      order.  Set LC_ALL=C or LC_ALL=POSIX to get the traditional sort order that uses native\r
+#      byte values.\r
+\r
+sub main {\r
+\r
+       my $cmdbuf;\r
+\r
+       # format of lines in test.fil:\r
+       # "F(1) $type(2) $state(3) $fh(4) $path(5) $pathcnt(6) $attrOrig(7-14) $attr()\r
+       # attrOrig: ($size(7) $mode(8) $op(9) $atime(10) $mtime(11) $ctime(12) $nlink(13) $ts(14))\r
+       # attrLast: ($size(15) $mode(16) $op(17) $atime(18) $mtime(19) $ctime(20) $nlink(21) $ts(22))\r
+\r
+       # skip comment lines\r
+       # if (path_count ($6) == 0 or original_op($9) == "create" or "mkdir" or "symlink") skip the file \r
+\r
+       $cmdbuf = 'gawk \' !/^[#]/ { if ($6 != "0") print $0 }\'  test.fil > all.fil';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # sort the test.fil according to path name\r
+       $cmdbuf = 'export LC_ALL=C; sort -k 5,5 all.fil > all.fil.order; echo $LC_ALL';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # keep the interested field only\r
+       # 2(D/F) 4(FH) 5(path) 6(count) 15(size_last) 21(nlink_last) 14(ts_s) 22(ts_e)\r
+       $cmdbuf = 'gawk \' { print $14, $22, $4, $5, $15, $21}\'  all.fil.order > fh-path-map-all';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # skip comment lines\r
+       # if (path_count ($6) == 0 or original_op($9) == "create" or "mkdir" or "symlink") skip the file \r
+\r
+       $cmdbuf = 'gawk \' !/^[#]/ { if ($6 != "0" && $9 != "create" && $9 != "mkdir" && $9 != "symlink") print $0 }\'  test.fil > active.fil';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       # sort the active.fil according to path name\r
+       $cmdbuf = 'export LC_ALL=C; sort -k 5,5 active.fil > active.fil.order; echo $LC_ALL';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # keep the interested field only\r
+       # 2(D/F) 4(FH) 5(path) 6(count) 7(size) 8(mode) 13(nlink)\r
+       $cmdbuf = 'gawk \' { print $2, $4, $5, $6, $7, $8 }\'  active.fil.order > active';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       $cmdbuf = 'gawk \' { print $4, $5, $7, $13}\'  active.fil.order > fh-path-map';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       # format output files\r
+       $cmdbuf = 'export LC_ALL=C; mv noattrdirdiscard noattrdirdiscard-tmp; sort -u -k 1,1 noattrdirdiscard-tmp > noattrdirdiscard; echo $LC_ALL; rm -f noattrdirdiscard-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       $cmdbuf = 'export LC_ALL=C; mv noattrdir-root noattrdir-root-tmp; sort -u -k 1,1 noattrdir-root-tmp > noattrdir-root; echo $LC_ALL; rm -f noattrdir-root-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+\r
+       #$cmdbuf = 'mv noattrdirdiscard noattrdirdiscard-tmp; cat  noattrdirdiscard-tmp missdiscardfh >noattrdirdiscard; rm -f noattrdirdiscard-tmp missdiscardfh';\r
+       $cmdbuf = 'mv noattrdirdiscard noattrdirdiscard-tmp; cat  noattrdirdiscard-tmp missdiscardfh >noattrdirdiscard; rm -f noattrdirdiscard-tmp';\r
+       print "$cmdbuf\n";\r
+       system $cmdbuf;\r
+       \r
+       #exit(0);\r
+       \r
+       # so far, you got the following information\r
+       # in active: all files/dirs active \r
+       # in noattrdir-root: a set of fhs pointing to RFSNN0\r
+       # in rfsinfo: a set of dir fhs refer to RFSNNxxx(>0)\r
+       #                a set of file fhs should be discard due to short of information\r
+\r
+       # create the active fs\r
+       # 1. BASEDIR/RFSNN0\r
+       # 2. BASEDIR/active\r
+       $cmdbuf = "mkdir -p RFSFS/RFSNN0";\r
+       system $cmdbuf;\r
+       open RFS_ACTIVE, "active" || die "open active failed\n";\r
+       while (<RFS_ACTIVE>) {\r
+               chop;\r
+               my ($type, $fh, $path, $pathcnt, $sizeHexStr, $mode) = split (' ', $_, 7);\r
+               if ($type==2) {\r
+                       $cmdbuf = "mkdir -p RFSFS$path";\r
+                       system $cmdbuf;\r
+               }elsif ($type==1){\r
+                       &rfsCreateFile("RFSFS$path", $pathcnt, $sizeHexStr);\r
+               }elsif ($type==5){\r
+                       #print STDERR "SYMLINK: $type fh: $fh path: $path\n";\r
+                       &rfsCreateSymlink("RFSFS$path", $pathcnt, $sizeHexStr);\r
+               }else {\r
+                       print STDERR "special file: $type fh: $fh path: $path\n";\r
+               }\r
+\r
+               my $line_num=0;\r
+               $line_num++;\r
+               if ( ($line_num %100)==0 ) {\r
+                       print STDERR "$line_num\n";\r
+               }\r
+               \r
+       }\r
+\r
+       # create map table: key (fh), value (path/fn)\r
+\r
+       # check whether there is fh that is not mapped to any path/fn in the trace\r
+\r
+       # simulate a replay of trace\r
+\r
+       return;\r
+       \r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_init/test.cnt b/TBBT/trace_init/test.cnt
new file mode 100644 (file)
index 0000000..e78f658
--- /dev/null
@@ -0,0 +1,2 @@
+#cmdline nfsscan.pl 
+#C time client fh euid egid TOTAL INTERESTING read write lookup getattr access create remove
diff --git a/TBBT/trace_init/test.fil b/TBBT/trace_init/test.fil
new file mode 100755 (executable)
index 0000000..429a873
--- /dev/null
@@ -0,0 +1 @@
+#cmdline nfsscan.pl 
diff --git a/TBBT/trace_init/userUtils.pl b/TBBT/trace_init/userUtils.pl
new file mode 100755 (executable)
index 0000000..4019d5d
--- /dev/null
@@ -0,0 +1,87 @@
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: userUtils.pl,v 1.5 2003/07/26 20:52:04 ellard Exp $\r
+#\r
+# utils.pl - deal with details like turning login names into uids.\r
+#\r
+\r
+sub logins2uids {\r
+       my ($str) = @_;\r
+\r
+       my @uids = ();\r
+       my @logins = split (/,/, $str);\r
+\r
+       my $j = 0;\r
+       for (my $i = 0; $i < @logins; $i++) {\r
+               if ($logins[$i] =~ /^[0-9]/) {\r
+                       $uids[$j++] = $logins[$i];\r
+               }\r
+               else {\r
+                       my ($login, $pw, $uid, $gid) = getpwnam ($logins[$i]);\r
+                       if (defined $uid) {\r
+                               $uids[$j++] = $uid;\r
+                       }\r
+                       else {\r
+                               # &&& Warning or error?\r
+                               print STDERR "WARNING: Unrecognized login ($logins[$i])\n";\r
+                               $uids[$j++] = $logins[$i];\r
+                       }\r
+               }\r
+       }\r
+\r
+       return (@uids);\r
+}\r
+\r
+sub groups2gids {\r
+       my ($str) = @_;\r
+\r
+       my @gids = ();\r
+       my @groups = split (/,/, $str);\r
+\r
+       for (my $i = 0; $i < @groups; $i++) {\r
+               if ($groups[$i] =~ /^[0-9]/) {\r
+                       $gids[$j++] = $groups[$i];\r
+               }\r
+               else {\r
+                       my $gid = getgrnam ($groups[$i]);\r
+                       if (defined $gid) {\r
+                               $gids[$j++] = $gid;\r
+                       }\r
+                       else {\r
+                               # &&& Warning or error?\r
+                               print STDERR "WARNING: Unrecognized group ($logins[$i])\n";\r
+                               $gids[$j++] = $groups[$i];\r
+                       }\r
+               }\r
+       }\r
+\r
+       return (@gids);\r
+}\r
+\r
+1;\r
diff --git a/TBBT/trace_play/Makefile.org b/TBBT/trace_play/Makefile.org
new file mode 100644 (file)
index 0000000..d019a0b
--- /dev/null
@@ -0,0 +1,328 @@
+#
+#      @(#)Makefile    2.1     97/10/23
+#
+# Makefile to build SFS benchmark suite
+#
+#
+#    Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+#      All rights reserved.
+#              Standard Performance Evaluation Corporation (SPEC)
+#              6585 Merchant Place, Suite 100
+#              Warrenton, VA 20187
+#
+#      This tape contains benchmarks acquired from several sources who
+#      understand and agree with SPEC's goal of creating fair and objective
+#      benchmarks to measure computer performance.
+#
+#      This copyright notice is placed here only to protect SPEC in the
+#      event the source is misused in any manner that is contrary to the
+#      spirit, the goals and the intent of SPEC.
+#
+#      The source code is provided to the user or company under the license
+#      agreement for the SPEC Benchmark Suite for this tape.
+#
+#
+# *****************************************************************
+# *                                                              *
+# *    Copyright 1991,1992  Legato Systems, Inc.                 *
+# *    Copyright 1991,1992  Auspex Systems, Inc.                 *
+# *    Copyright 1991,1992  Data General Corporation             *
+# *    Copyright 1991,1992  Digital Equipment Corporation        *
+# *    Copyright 1991,1992  Interphase Corporation               *
+# *    Copyright 1991,1992  Sun Microsystems, Inc.               *
+# *                                                               *
+# *****************************************************************
+
+#
+# -----------------------  How to use this makefile  --------------------
+#
+# The makefile is divided into 10 sections:
+#  1) basic information
+#  2) default compiler definitions
+#  3) vendor specific definitions
+#  4) OS feature specific definitions
+#  5) final compiler definitions (includes specific vendor and feature defs)
+#  6) source file definitions
+#  7) object file definitions
+#  8) rules and targets for building sfs
+#  9) lint, install, clean, misc rules
+
+
+# ----------------------  default compiler definitions  -----------------
+#
+# For Solaris 2.X (SunOS 5.X) or later
+MACHID = solaris2
+CC=cc
+OPT = -O
+CFLAGS = -v -Xc -D__sparc -D_POSIX_SOURCE
+LDFLAGS =
+EXTRA_CFLAGS = -DPORTMAP
+EXTRA_LDFLAGS =
+EXTRA_LINTFLAGS =
+EXTRA_LIBS =
+RESVPORT_MOUNT=
+OSTYPE = -DSVR4 -DSOLARIS2
+INCDIR = -I.
+RPCLIB = rpc/librpclib.a
+LIBS = -lm -lsocket -lnsl
+
+#
+# ----------------------  OS feature specific definitions  ------------------
+#
+
+#
+# A UNIX derivative that only supports the getfsent(3) family of calls
+# should have the USEFSTAB variable set.
+# A UNIX derivative that supports the getmntent(3) family of calls
+# should have the line commented out.
+#FSTAB = -DUSEFSTAB
+
+# SFS uses the setsid(2) system call to form a new proces group
+# This prevents 'synchronization' signals from causing parent shell (sh)
+# to exit. SETPGRP_CALL allows you to specify the alternative use
+# of the setpgrp(2) and which variation you are using. 
+
+# If you are linking with BSD libraries then uncomment the next line.
+# SETPGRP_CALL = -DSETPGRP_BSD
+
+# If you are linking with SYSV type libraries then uncomment the next line.
+#SETPGRP_CALL = -DSETPGRP_SYSV
+
+# if your client is failing the mount even when run as root then you should
+# uncomment the RESVPORT_MOUNT to explicitly bind to a reserved port.
+# RESVPORT_MOUNT = -DRESVPORT
+
+#
+# ----------------------  final compiler definitions  -----------------------
+#
+
+# DEBUG = -g
+CFLAGS = 
+EXTRA_CFLAGS =
+
+LDFLAGS =  $(OSTYPE)
+
+
+#
+# ----------------------  source file definitions  ------------------
+#
+
+MAKEFILE =     Makefile
+
+DOC =          sfs.1 README sfs.1
+
+SHELLFILES =   sfs_mgr sfs_mcr sfs_rc 
+
+V2_HDR =       sfs_c_def.h sfs_c_nfs.h
+
+V3_HDR =       sfs_c_def.h sfs_c_nfs.h
+
+V2_SRC =       sfs_2_ops.c sfs_2_vld.c
+
+V3_SRC =       sfs_3_ops.c sfs_3_vld.c
+
+C_SRC =                sfs_c_clk.c sfs_c_dat.c sfs_c_dmp.c sfs_c_man.c \
+               sfs_c_pnt.c sfs_c_rnd.c sfs_c_sig.c sfs_c_bio.c \
+               sfs_2_xdr.c sfs_3_xdr.c sfs_c_mnt.c sfs_c_chd.c \
+               sfs_c_clnt.c
+
+C_COMMON_SRC = sfs_c_sub.c
+
+M_HDR =                sfs_m_def.h
+
+M_PRIME_SRC =  sfs_m_prm.c
+
+M_SYNCD_SRC =  sfs_m_snc.c
+
+M_MSG_SRC =    sfs_m_msg.c
+
+M_COMMON_SRC = sfs_m_xdr.c
+
+#
+# ----------------------  object file definitions  -------------------
+#
+
+V2_OBJ =       sfs_2_ops.o sfs_2_vld.o
+
+V3_OBJ =       sfs_3_ops.o sfs_3_vld.o
+
+C_OBJ =                sfs_c_clk.o sfs_c_dat.o sfs_c_dmp.o sfs_c_man.o \
+               sfs_c_pnt.o sfs_c_rnd.o sfs_c_sig.o sfs_c_bio.o \
+               sfs_2_xdr.o sfs_3_xdr.o sfs_c_mnt.o sfs_c_chd.o \
+               sfs_c_clnt.o
+
+C_COMMON_OBJ = sfs_c_sub.o
+
+
+M_PRIME_OBJ =  sfs_m_prm.o
+
+M_SYNCD_OBJ =  sfs_m_snc.o
+
+M_MSG_OBJ =    sfs_m_msg.o
+
+M_COMMON_OBJ = sfs_m_xdr.o
+
+#
+# ----------------------  rules and targets for building sfs  ---------
+#
+
+BENCH = /tmp/spec
+all:           fix_perm install
+
+compile:       fix_perm install
+
+fix_perm:
+               chmod 755 $(BENCH)/src
+               chmod 755 $(BENCH)/src/rpc
+               chmod 755 $(BENCH)/bin
+
+sfs:           $(V2_HDR) $(M_HDR) $(V2_OBJ) $(C_OBJ) \
+               $(C_COMMON_OBJ) $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB)
+               $(CC) -o $@ $(LDFLAGS) $(V2_OBJ) $(C_OBJ) $(C_COMMON_OBJ) \
+                       $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB) $(LIBS) \
+                       $(EXTRA_LIBS) 
+
+sfs3:  $(V3_HDR) $(M_HDR) $(V3_OBJ) $(C_OBJ) \
+               $(C_COMMON_OBJ) $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB)
+               $(CC) -o $@ $(LDFLAGS) $(V3_OBJ) $(C_OBJ) $(C_COMMON_OBJ) \
+                       $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB) $(LIBS) \
+                       $(EXTRA_LIBS) 
+
+sfs_prime:     $(V2_HDR) $(M_HDR) $(M_PRIME_OBJ) \
+               $(C_COMMON_OBJ) $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB)
+               $(CC) -o $@ $(LDFLAGS) $(M_PRIME_OBJ) $(C_COMMON_OBJ) \
+                       $(M_COMMON_OBJ) $(M_MSG_OBJ) $(RPCLIB) $(LIBS) \
+                       $(EXTRA_LIBS) 
+
+sfs_syncd:     $(V2_HDR) $(M_HDR) $(M_SYNCD_OBJ) \
+               $(C_COMMON_OBJ) $(M_COMMON_OBJ) $(RPCLIB)
+               $(CC) -o $@ $(LDFLAGS) $(M_SYNCD_OBJ) $(C_COMMON_OBJ) \
+                       $(M_COMMON_OBJ) $(RPCLIB) $(LIBS) $(EXTRA_LIBS) 
+
+.c.o:
+               $(CC) -c $(INCDIR) $(CFLAGS) $(EXTRA_CFLAGS) $(DEBUG) \
+                       $(SETPGRP_CALL) $(FSTAB) $(OSTYPE) $(OPT) \
+                       $(RESVPORT_MOUNT) $*.c
+
+${RPCLIB}: FRC
+       @cd rpc; make MACHID="${MACHID}"\
+               CC="${CC}" CFLAGS="${CFLAGS}" \
+               LDFLAGS="${LDFLAGS}" EXTRA_CFLAGS="${EXTRA_CFLAGS}" \
+               EXTRA_LDFLAGS="${EXTRA_LDFLAGS}" EXTRA_LIBS="${EXTRA_LIBS}" \
+               LIBS="${LIBS}" OSTYPE="${OSTYPE}" OPT="${OPT}" \
+               EXTRA_LINTFLAGS="${EXTRA_LINTFLAGS}" \
+               RESVPORT_MOUNT="${RESVPORT_MOUNT}"\
+               librpclib.a
+
+sfs_3_ops.o:   sfs_c_nfs.h sfs_c_def.h sfs_3_ops.c
+
+sfs_3_vld.o:   sfs_c_nfs.h sfs_c_def.h sfs_3_vld.c
+
+sfs_3_xdr.o:   sfs_c_nfs.h sfs_c_def.h sfs_3_xdr.c
+
+sfs_c_bio.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_bio.c
+
+sfs_c_chd.o:   sfs_c_nfs.h sfs_c_def.h sfs_m_def.h sfs_c_chd.c
+
+sfs_c_clk.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_clk.c
+
+sfs_c_clnt.o:  sfs_c_nfs.h sfs_c_def.h sfs_c_clnt.c
+
+sfs_c_dat.o:   sfs_c_def.h sfs_m_def.h sfs_c_nfs.h sfs_c_dat.c
+
+sfs_c_dmp.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_dmp.c
+
+sfs_c_man.o:   sfs_c_nfs.h sfs_c_def.h \
+               sfs_m_def.h sfs_c_man.c
+
+sfs_c_mnt.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_mnt.c
+
+sfs_2_ops.o:   sfs_c_nfs.h sfs_c_def.h sfs_2_ops.c
+
+sfs_c_pnt.o:   sfs_c_nfs.h sfs_c_def.h \
+               sfs_m_def.h sfs_c_pnt.c
+
+sfs_c_rnd.o:   sfs_c_rnd.c
+
+sfs_c_sig.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_sig.c
+
+sfs_c_sub.o:   sfs_c_nfs.h sfs_c_def.h sfs_c_sub.c
+
+sfs_2_vld.o:   sfs_c_nfs.h sfs_c_def.h sfs_2_vld.c
+
+sfs_2_xdr.o:   sfs_c_nfs.h sfs_c_def.h sfs_2_xdr.c
+
+sfs_m_msg.o:   sfs_c_nfs.h sfs_c_def.h \
+               sfs_m_def.h sfs_m_msg.c
+
+sfs_m_prm.o:   sfs_c_nfs.h sfs_c_def.h \
+               sfs_m_def.h sfs_m_prm.c
+
+sfs_m_snc.o:   sfs_c_nfs.h sfs_c_def.h \
+               sfs_m_def.h sfs_m_snc.c
+
+sfs_m_xdr.o:   sfs_m_def.h sfs_m_xdr.c
+
+#
+# ----------------------  lint, install, clean, misc rules  -----------------
+#
+
+lint:          lint_sfs lint_sfs3 lint_prime lint_syncd
+
+lint_sfs:      $(V2_HDR) $(M_HDR) $(V2_SRC) $(C_SRC) \
+               $(C_COMMON_SRC) $(M_COMMON_SRC) $(M_MSG_SRC)
+               lint -Dlint $(INCDIR) $(CFLAGS) $(EXTRA_CFLAGS) $(DEBUG) \
+                       $(EXTRA_LINTFLAGS) \
+                       $(SETPGRP_CALL) $(FSTAB) $(OSTYPE) \
+                       $(RESVPORT_MOUNT) \
+                       $(V2_SRC) $(C_SRC) $(C_COMMON_SRC) \
+                       $(M_COMMON_SRC) $(M_MSG_SRC) \
+                       $(LIBS) $(EXTRA_LIBS) \
+                       > sfs.lint
+
+lint_prime:    $(V2_HDR) $(M_HDR) $(M_PRIME_SRC) \
+               $(C_COMMON_SRC) $(M_COMMON_SRC) $(M_MSG_SRC)
+               lint -Dlint $(INCDIR) $(CFLAGS) $(EXTRA_CFLAGS) $(DEBUG) \
+                       $(EXTRA_LINTFLAGS) \
+                       $(SETPGRP_CALL) $(FSTAB) $(OSTYPE) \
+                       $(RESVPORT_MOUNT) \
+                       $(M_PRIME_SRC) $(C_COMMON_SRC) \
+                       $(M_COMMON_SRC) $(M_MSG_SRC) \
+                       $(LIBS) $(EXTRA_LIBS) \
+                       > sfs_prime.lint
+
+lint_syncd:    $(V2_HDR) $(M_HDR) $(M_SYNCD_SRC) \
+               $(C_COMMON_SRC) $(M_COMMON_SRC)
+               lint -Dlint $(INCDIR) $(CFLAGS) $(EXTRA_CFLAGS) $(DEBUG) \
+                       $(EXTRA_LINTFLAGS) \
+                       $(SETPGRP_CALL) $(FSTAB) $(OSTYPE) \
+                       $(RESVPORT_MOUNT) \
+                       $(M_SYNCD_SRC) $(C_COMMON_SRC) $(M_COMMON_SRC) \
+                       $(LIBS) $(EXTRA_LIBS) \
+                       > sfs_syncd.lint
+
+lint_sfs3:     $(V3_HDR) $(M_HDR) $(V3_SRC) $(C_SRC) \
+               $(C_COMMON_SRC) $(M_COMMON_SRC) $(M_MSG_SRC)
+               lint -Dlint $(INCDIR) $(CFLAGS) $(EXTRA_CFLAGS) $(DEBUG) \
+                       $(EXTRA_LINTFLAGS) \
+                       $(SETPGRP_CALL) $(FSTAB) $(OSTYPE) \
+                       $(RESVPORT_MOUNT) \
+                       $(V3_SRC) $(C_SRC) $(C_COMMON_SRC) \
+                       $(M_COMMON_SRC) $(M_MSG_SRC) \
+                       $(LIBS) $(EXTRA_LIBS) \
+                       > sfs3.lint
+
+install:       sfs sfs3 sfs_syncd sfs_prime
+               chmod +x sfs_syncd sfs_prime \
+                       sfs_mgr sfs_mcr sfs_ext_mon \
+                       sfs_suchown sfs sfs3
+               ./sfs_suchown $(RESVPORT_MOUNT) sfs sfs3
+
+clean clobber:
+               rm -f *.o sfs sfs_syncd sfs_prime \
+                       sfs3 sfs_prime \
+                       lint.out sfs_*.shr1 core *.lint
+               cd rpc; make clean
+               ./sfs_suchown clobber
+
+FRC:
diff --git a/TBBT/trace_play/README b/TBBT/trace_play/README
new file mode 100644 (file)
index 0000000..e340761
--- /dev/null
@@ -0,0 +1,10 @@
+
+The trace player executable is sfs3. For trace player to run, the owner of the
+executable has to be root.
+
+To make the executable:
+       make sfs3
+
+The change owner:
+       su - 
+       chown root:root sfs3
diff --git a/TBBT/trace_play/README.old b/TBBT/trace_play/README.old
new file mode 100644 (file)
index 0000000..3f31fff
--- /dev/null
@@ -0,0 +1,140 @@
+A few notes about the redesign of the file selection algorithm for
+SFS 3.0, which may be incorporated into the inline comments in the
+next maintenance release.
+
+
+Q1.  How is the Poisson Distribution used in SFS?
+
+A1. The probabilities from a Poisson-derived distribution are used
+to select files from the I/O working-set in a non-uniform fashion.
+
+The load-generators are not Poisson Processes.  In particular, their
+inter-request times are not exponentially-distributed; they are programmed
+to have uniformly distributed think-times, which are only approximately
+achieved, due to limitations of the load-generating client and its
+operating system.
+
+Q2.  Why is a Poisson Distribution used in SFS, rather than, say a
+Zipf distribution?
+
+A2.  The reasoning behind the use of Poisson probabilities in SFS 2.0
+may be lost in the mists of time.  Because SFS 2.0 was withdrawn by SPEC
+before SFS 3.0 development had proceeded very far, there was considerable
+time-pressure to release SFS 3.0 quickly.  So we chose to patch the
+existing Poisson probability calculations instead of implementing a new
+distribution for file accesses.
+
+There is experimental data showing that a Zipf Distribution is a good
+model for file access probabilities.  The question of what distribution
+to use in SFS 4.0 is open, so various distributions can be considered.
+
+Q3.  Is it true that SFS 3.0 combines multiple Poisson cycles into a
+single cycle that is also a Poisson Distribution?
+
+A3.  The combination of the distributions follows the curve of a Poisson
+Distribution only if you treat each of the twelve generations of
+access-groups as a single outcome.
+
+Q4.  Why did the calculation of "Io_working_set.access_group_cnt" change 
+between SFS 2.0 and SFS 3.0?
+
+A4.  This calculation determines the number of access-groups in the I/O
+working-set.  The number of access-groups grows *roughly* in linear
+proportion to the number of files, so that no access-group contains more
+than 125 files.
+
+In SFS 2.0, 4 groups are added for every 500 files, but in SFS 3.0
+12 groups are added for every 1500 files, so the number of files per
+access-group remains roughly the same.
+
+The main effect of the change is how the number of groups is rounded.
+In SFS 2.0, the number of groups was rounded to a multiple of 4,
+with a minimum of 8 groups.  In SFS 3.0, the number of groups is
+rounded to a multiple of 12 (the value of "generations") so that the
+cycle of Poisson probabilities (for all 12 generations of access-groups)
+will be completely repeated group_cnt/12 times with no groups left over.
+
+Q5.  Why was the minimum number of access-groups changed from 8 to 12?
+Why not, say, 24?
+
+A5.  The choice was somewhat arbitrary.  Here is some of the rationale:
+
+In order to get a complete set of Poisson probabilities, there must be
+at least as many access-groups as generations.  If we had generations=24
+instead of 12, then some of the group-probabilities would be zero due to
+defect #2.  (Recall that with 24 groups in SFS 2.0, 13% were inaccessible
+due to rounding of the scaled probabilities.)  In SFS 2.0, 12 was the
+largest number of groups which did not trigger defect #2.  Of course,
+since we now know how to fix that defect, that wasn't the complete reason.
+
+Another consideration was that the number of access groups must be rounded
+to a multiple of the number of generations.  If we had used generations=24
+then the rounding would introduce a more radical change in the number
+of groups, especially for large numbers of procs.
+
+On the other hand, if we had used generations=8 instead of 12, we would
+have gotten very little variation in access probabilities, which seemed
+against the intent of the benchmark design.
+
+Q6.  Why is lambda being calculated differently in SFS 3.0?
+
+A6.  Lambda is the parameter of the Poisson Distribution which determines
+the shape of its probability density function, its mean, and other
+characteristics.
+
+SFS 2.0 set lambda to half the number of groups, which in turn was a
+function of the requested ops/sec/proc.  That was defect #4, which caused
+the shape of the access-distribution to change depending on how many
+processes a vendor chose to use -- it would get narrower as the number
+of processes was reduced.  SFS 3.0 sets lambda based on "generations",
+which is a constant.  Thus the new distribution has the same shape no
+matter how many load-generating processes are used.
+
+The key to defect #4 was that we *don't* want lambda to vary
+with the number of access-groups.  We want it to be a constant so that
+for a given size fileset the number of files that fit into cache 
+depends very little on the number of load-generation processes used.
+
+Q7.  Why was lambda set to half the number of groups in SFS 2.0
+instead of something else? 
+
+A7.  The SFS 2.0 rationale is not documented, as far as we know.  The nice
+thing about group_count/2 is that it puts the characteristic "hump" of the
+probability density function (the mode) near group_count/2, in the middle
+of the array of groups.  Probably that was the reason.
+
+In SFS 3.0, each cycle of probabilities has 12 groups, so lambda=6
+to preserve this feature of the distribution.
+
+Q8.  How is the SFS 3.0 approach differ from always using 12 access-groups
+and allowing the number of files per access-group to be more than 125?
+
+A8.  The end-result would have been roughly the same.  The reason this
+was not done was that SFS sometimes searches within an access-group, for
+instance to find the best fit for an operation.  The search is a linear
+search.  We were concerned that if the number of files in a group got
+too large, the client could get bogged down searching for the best fit.
+The search for the appropriate access-group is a binary search, which
+scales better.
+
+Q9.  Why not just limit the benchmark to 25 requested ops/second/process,
+so that the number of groups would always be 12 or less?
+A9.  Historically SPEC has given server vendors lots of leeway to
+have as few processes as they wish, modulo the Uniform Access Rule and
+the run-rule requirement for at least 8 processes per network.  In the
+interest of avoiding a long, drawn-out debate about adding a new run-rule
+to arbitrarily limit ops/process, we decided to simply fix the code so
+that it would work reasonably well for larger numbers of ops/process.
+
+Q10.  Where did the new variable "cumulative_ratio" come from?
+
+A10.  This variable is used in the loop that calculates Poisson distribution
+for I/O working-set accesses.  In 2.0, lambda^x and x! were calculated
+separately.  Both variables got very large and would overflow when 'x' got
+into the hundreds.  This was defect #3.  The Poisson distribution really
+only needs the ratio (lambda^x/x!), which is numerically more stable.
+So that is what the SFS 3.0 code calculates.
+
+Since SFS 3.0 never uses values of lambda other than 6.0, the change
+has proven to be moot.
diff --git a/TBBT/trace_play/agefs b/TBBT/trace_play/agefs
new file mode 100755 (executable)
index 0000000..bdebf34
Binary files /dev/null and b/TBBT/trace_play/agefs differ
diff --git a/TBBT/trace_play/agefs.log b/TBBT/trace_play/agefs.log
new file mode 100644 (file)
index 0000000..d3fcb00
--- /dev/null
@@ -0,0 +1,36 @@
+
+
+agefs Wed Apr 21 18:28:42 EDT 2004
+
+
+agefs Wed Apr 21 18:31:44 EDT 2004
+Wed Apr 21 18:31:44 EDT 2004
+
+
+agefs Wed Apr 21 18:32:06 EDT 2004
+Wed Apr 21 18:32:06 EDT 2004
+
+
+agefs Wed Apr 21 18:32:58 EDT 2004
+Wed Apr 21 18:32:58 EDT 2004
+
+
+agefs Wed Apr 21 18:33:15 EDT 2004
+Wed Apr 21 18:33:15 EDT 2004
+Wed Apr 21 23:18:15 EDT 2004
+Wed Apr 21 23:18:15 EDT 2004
+Thu Apr 22 00:08:24 EDT 2004
+Thu Apr 22 00:08:24 EDT 2004
+Thu Apr 22 00:33:15 EDT 2004
+Thu Apr 22 00:33:15 EDT 2004
+Thu Apr 22 00:33:33 EDT 2004
+Thu Apr 22 00:33:33 EDT 2004
+Thu Apr 22 00:35:06 EDT 2004
+Thu Apr 22 00:35:06 EDT 2004
+Thu Apr 22 00:35:16 EDT 2004
+Thu Apr 22 00:35:16 EDT 2004
+Thu Apr 22 00:36:25 EDT 2004
+Thu Apr 22 00:38:36 EDT 2004
+Thu Apr 22 00:39:17 EDT 2004
+Thu Apr 22 00:39:19 EDT 2004
+Thu Apr 22 00:47:43 EDT 2004
diff --git a/TBBT/trace_play/frag_collect b/TBBT/trace_play/frag_collect
new file mode 100755 (executable)
index 0000000..773e158
--- /dev/null
@@ -0,0 +1,15 @@
+nfs stop
+umount $1
+mount $1
+nfs start
+cd $1
+echo "find test1 -print >$3.1"
+find test1 -print > $3.1
+echo "sed -d s/^/show_inode_info / $3.1"
+sed -e "s/^/show_inode_info /" $3.1 >$3.2
+echo "open $2" >$3.3
+cat $3.2 >> $3.3
+echo "debugfs -f $3.3"
+debugfs -f $3.3 > $3.4
+#echo "frag_count $3.4 > $3.5"
+#frag_count $3.4 > $3.5
diff --git a/TBBT/trace_play/frag_collect_cust b/TBBT/trace_play/frag_collect_cust
new file mode 100755 (executable)
index 0000000..24d9c62
--- /dev/null
@@ -0,0 +1,14 @@
+#This is to collect info for something other than test1
+#test1 is hard-coded in frag_collect
+nfs stop
+umount $1
+mount $1
+nfs start
+echo "sed -d s/^/show_inode_info / $3"
+sed -e "s/^/show_inode_info /" $3 >$3.2
+echo "open $2" >$3.3
+cat $3.2 >> $3.3
+echo "debugfs -f $3.3"
+debugfs -f $3.3 > $3.4
+#echo "frag_count $3.4 > $3.5"
+#frag_count $3.4 > $3.5
diff --git a/TBBT/trace_play/frag_count b/TBBT/trace_play/frag_count
new file mode 100755 (executable)
index 0000000..e1cdae0
Binary files /dev/null and b/TBBT/trace_play/frag_count differ
diff --git a/TBBT/trace_play/frag_count.c b/TBBT/trace_play/frag_count.c
new file mode 100644 (file)
index 0000000..a8d8397
--- /dev/null
@@ -0,0 +1,311 @@
+#include <stdio.h>
+#define RFS_ASSERT(condition)                                       \
+    if (!(condition)) {                                             \
+        fprintf(stderr, "Assertion failed: line %d, file \"%s\"\n", \
+                        __LINE__, __FILE__);                        \
+        fflush(stdout); \
+        fflush(stderr); \
+        exit(-1); \
+    }
+
+#define DISK_BLOCK_SIZE 4096
+#define SUB_DISTANCE
+int f()
+{}
+char buf[8024000];
+main(int argc, char ** argv)
+{
+       FILE * fp;
+       int ret;
+       char * p;
+       int i;
+       int frag_num, distance, tfrag_num=0;
+       int td=0, td_MB=0;
+       int max_block_num = -1;
+       int block_num = -1;
+       int last_block_num;
+       int tblock_num =0;
+       int last_block = 0;
+       int block_range_start, block_range_stop;
+       int lineno = 0;
+       int format_version = 1;
+       char * p1=NULL, *p2=NULL, *p3=NULL;
+       int size = -1;
+       int max_block = 0;
+       FILE * fpout;
+       char name[1024];
+       int file_num = 0;
+       unsigned long long distancell = 0;
+       int avg_frag_distance;
+       int avg_block_distance;
+#ifdef SUB_DISTANCE
+#define MAX_SUB_DISTANCE_NUM 50
+       int sub_distance_index;
+       int SUB_DISTANCE_NUM = 1;
+       int SUB_DISTANCE_SIZE = 1000000;
+       unsigned long long sub_distance[MAX_SUB_DISTANCE_NUM];
+       unsigned int sub_frag_num[MAX_SUB_DISTANCE_NUM], sub_block_num[MAX_SUB_DISTANCE_NUM];
+       memset (&sub_distance, 0, sizeof(sub_distance));
+       memset (&sub_frag_num, 0, sizeof(sub_frag_num));
+       memset (&sub_block_num, 0, sizeof(sub_block_num));
+
+       if (argc == 3) {
+               SUB_DISTANCE_NUM = atoi(argv[2]);
+               RFS_ASSERT ((SUB_DISTANCE_NUM >=1) && (SUB_DISTANCE_NUM <= MAX_SUB_DISTANCE_NUM));
+       }
+#endif
+
+       fp = fopen (argv[1], "r");
+    if (!fp) {
+        printf ("can not opern %s\n", argv[1]);
+        perror("open");
+        exit (0);
+    }
+
+
+       strcpy (name, argv[1]);
+       strcat (name, ".disk");
+
+       fpout = fopen(name, "w");
+       if (!fpout) {
+        printf ("can not opern %s\n", name);
+        perror("open");
+        exit (0);
+       }
+       
+       while (fgets(buf, sizeof(buf), fp)) {
+               lineno++;
+               if ((lineno%10000)==0) { // || (lineno >630000)) {
+                       fprintf(stderr, "%d lines processed\n", lineno);
+               }
+               if (lineno==122165)
+                       f();
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               if (buf[0]=='U') {
+                       p = strstr (buf, "Size");
+                       RFS_ASSERT (p);
+                       if (size != -1) {
+                               printf ("lineno %d size %d\n", lineno, size);
+                       }
+                       RFS_ASSERT (size == -1);
+                       sscanf(p, "Size: %d", &size);
+                       continue;
+               }
+
+
+               /* For now we ignore symbolic links */
+               if (!strncmp(buf, "Fast_link_dest", strlen("Fast_link_dest")))  {
+                       f();
+                       goto ENDLOOP;
+               }
+
+               if (buf[0]!='B')
+                       continue;
+
+               RFS_ASSERT (!strcmp(buf, "BLOCKS:\n"));
+               fgets(buf, sizeof(buf), fp);
+               lineno++;
+               if (!(buf[strlen(buf)-1]=='\n')) {
+                       printf ("line[%d] %s\n", lineno, buf);
+               };
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               if (!strcmp(buf, "\n"))
+                       goto ENDLOOP;
+
+
+               RFS_ASSERT (size >= 0);
+               RFS_ASSERT (block_num == -1);
+               RFS_ASSERT (max_block_num == -1);
+               block_num = 0; /* the block number of block_range_start of current fragment */
+               last_block_num = 0; /* the block number of block_range_start of last fragment */
+               max_block_num = 0;
+               if (size >0) {
+                       char line[1024];
+                       int i;
+                       fgets(line, sizeof(line), fp);
+                       lineno++;
+                       RFS_ASSERT (line[strlen(line)-1]=='\n');
+                       RFS_ASSERT (strstr(line, "TOTAL: "));
+                       max_block_num = atoi (line+strlen("TOTAL: "));
+                       i = ((size+DISK_BLOCK_SIZE-1)/DISK_BLOCK_SIZE);
+                       RFS_ASSERT ((max_block_num >= i) && ((max_block_num*9/i)<10));
+               }
+               tblock_num += max_block_num;
+
+               p = buf;
+               frag_num = 0;
+               distance = 0;
+               last_block = 0;
+               //printf ("line %d %s", lineno, buf);
+               while (p && (*p!='\n')) {
+                       if (format_version == 1) {
+                               p1 = strchr (p, ')');
+                               if (p1) {
+                                       p2 = strchr (p, '-');
+                                       p3 = strchr (p, ':');
+                                       RFS_ASSERT (p3);
+                                       p3++;
+                               } else {
+                                       format_version = 2;
+                                       p3 = p;
+                               }
+                       } else
+                               p3 = p;
+
+#define checkit
+                       /* single block range */
+                       if ((p2==NULL) || p2>p1) {      
+#ifdef checkit
+                               char * pt2, a;
+                               pt2 = strchr(p3, ' ');
+                               if (!pt2) {
+                                       pt2 = strchr(p3, '\n');
+                                       a = '\n';
+                               } else
+                                       a = ' ';
+                               RFS_ASSERT (pt2);
+                               RFS_ASSERT (pt2!=p3);
+                               *pt2 = 0;
+                               block_range_start = atoi (p3);
+                               *pt2 = a ;
+#else
+                               sscanf(p3, "%d", &block_range_start);
+#endif
+                               block_range_stop = block_range_start;
+                       } else {
+#ifdef checkit
+                               char * pt, * pt2, a;
+                               pt = strchr(p3, '-');
+                               RFS_ASSERT (pt);
+                               *pt = 0;
+                               block_range_start = atoi (p3);
+                               *pt = '-';
+                               pt2 = strchr(pt+1, ',');
+                               if (!pt2) {
+                                       pt2 = strchr(pt+1, '\n');
+                                       a = '\n';
+                               } else
+                                       a = ',';
+                               RFS_ASSERT (pt2);
+                               *pt2 = 0;
+                               block_range_stop = atoi (pt+1);
+                               *pt2 = a ;
+#else
+                               sscanf(p3, "%d-%d", &block_range_start, &block_range_stop);
+#endif
+                       }
+
+                       RFS_ASSERT (block_range_start >0);
+                       RFS_ASSERT (block_range_stop >= block_range_start);
+
+                       block_num += (block_range_stop - block_range_start+1);
+
+                       if (block_range_start != (last_block+1)) {
+                               frag_num ++;
+
+#ifdef SUB_DISTANCE
+                               sub_distance_index = (block_num-1) * SUB_DISTANCE_NUM/max_block_num;
+                               sub_block_num[sub_distance_index] += block_num - last_block_num;
+                               last_block_num = block_num;
+                               //printf ("block_num %d SUB_DISTANCE_NUM %d max_block_num %d index %d\n", block_num, SUB_DISTANCE_NUM,
+//max_block_num, sub_distance_index);
+                               RFS_ASSERT ((sub_distance_index>=0) && (sub_distance_index<SUB_DISTANCE_NUM));
+#endif
+                               if (last_block!=0) {
+                                       if (block_range_start > last_block+1) {
+                                               distance += block_range_start - (last_block+1);
+#ifdef SUB_DISTANCE
+                                               sub_distance[sub_distance_index] += block_range_start - (last_block+1);
+#endif
+                                       } else {
+                                               distance += (last_block+1)-block_range_start;
+#ifdef SUB_DISTANCE
+                                               sub_distance[sub_distance_index] += (last_block+1)-block_range_start ;
+#endif
+                                       }
+
+                                       if (distance >= 1000000000) {
+                                               printf ("line[%d] %s, block_range_start %d last_block %d\n", lineno, buf, block_range_start, last_block);
+                                               RFS_ASSERT (0);
+                                       }
+                                       fprintf(fpout, "%d %d\n", last_block, block_range_start);
+                               };
+                               //printf ("range_start %d last_block %d distance %d\n", 
+                                               //block_range_start, last_block, distance);
+#ifdef SUB_DISTANCE
+                               sub_frag_num[sub_distance_index] ++;
+#endif
+                       }
+                       
+                       last_block = block_range_stop;
+                       if (last_block > max_block)
+                               max_block = last_block;
+                       if (p1)
+                               p = strchr (p3, '(');
+                       else {
+                               p = strchr (p3, ' ');
+                               p++;
+                       }
+               }
+               //printf ("FRAG_NUM %d DISTANCE %d\n", frag_num, distance);
+               tfrag_num += frag_num;
+               distancell += distance;
+ENDLOOP:
+               file_num ++;
+               size = -1;
+               block_num = -1;
+               max_block_num = -1;
+/*
+               td += distance;
+               if (td > 1000000) {
+                       td_MB += td/1000000;
+                       td = td%1000000;
+                       RFS_ASSERT (td_MB < 1000000000);
+               }
+*/
+       }
+       fclose (fpout);
+       fclose (fp);
+                                                                              
+       if (tfrag_num != file_num) {
+               RFS_ASSERT ((distancell /(tfrag_num-file_num)) < 1000000000);
+               RFS_ASSERT ((distancell /(tblock_num-file_num)) < 1000000000);
+               avg_frag_distance = distancell/(tfrag_num-file_num);
+               avg_block_distance = distancell/(tblock_num-file_num);
+       } else {
+               avg_frag_distance =0;
+               avg_block_distance =0;
+       }
+       RFS_ASSERT ((distancell /1000000) < 1000000000);
+       td_MB = distancell/1000000;
+       td = distancell%1000000;
+       
+#ifdef SUB_DISTANCE
+       for (i=0; i<SUB_DISTANCE_NUM; i++) {
+               printf("sub[%d] block_num %d frag_num %d distance %d\n", i, sub_block_num[i], sub_frag_num[i], sub_distance[i]/1000000);
+       }
+#endif
+/*
+    distancell = td_MB;
+    distancell *=1000000;
+    distancell +=td;
+    distancell /= (tfrag_num-file_num);
+    if (distancell > 1000000000) {
+        printf ("error 4\n");
+        exit(-1);
+    }
+    avg_frag_distance = distancell;
+
+    distancell = td_MB;
+    distancell *=1000000;
+    distancell +=td;
+    distancell /= (tblock_num-file_num);
+    if (distancell > 1000000000) {
+        printf ("error 4\n");
+        exit(-1);
+    }
+    avg_block_distance = distancell;
+*/
+
+       printf("****total FRAG_NUM %d td_MB %d td %d tblock_num %d max_blockno %d file_num %d avg_frag_distance %d avg_block_distance %d\n", tfrag_num, td_MB, td, tblock_num, max_block, file_num, avg_frag_distance, avg_block_distance);
+}
diff --git a/TBBT/trace_play/fragment_collect b/TBBT/trace_play/fragment_collect
new file mode 100755 (executable)
index 0000000..9e5b8c9
--- /dev/null
@@ -0,0 +1,43 @@
+# Usage: fragment_collect dev mount_dir test_path output_file
+#
+# On linux system, this script collects the fragmentation status of a 
+# particular directory. The objects under this directory SHOULD NOT be 
+# used as mount point. If they do, please umount them first, but there
+# is no danger even if you forget. The "output_file" is the one that I
+# need, please gzip it and send it back to nzhu@cs.sunysb.edu
+#
+# The program needs to be run as ROOT, but it is SAFE and KEEPS PRIVACY.
+# The pathname information on your system is completely filtered out 
+# from the final output. This program ONLY READ and DOES NOT WRITE any
+# files EXCEPT "output_file*" 
+#
+# Parameters:
+#               dev                    :the device of the directory to be measured
+#               mount_dir              :the the mount point of the device
+#               test_path              :the relative path of the directory under mount_dir
+#               output_file    :where the result is stored.
+#
+# Example: fragment_collect /dev/hda7 /home ningning /tmp/home-ningning.frag
+#
+#      This gives the fragmentation information (saved in "/tmp/home-ningning.frag")
+#   of the file system objects under the directory of "/home/ningning" on the 
+#   disk partition of "/dev/hda7" mounted to "/home".
+#
+#nfs stop
+#umount $2
+#mount $2
+#nfs start
+cd $2
+echo "find $3 -print >$4.1"
+find $3 -print > $4.1
+echo "sed -d s/^/show_inode_info / $4.1"
+sed -e "s/^/show_inode_info /" $4.1 >$4.2
+echo "open $1" >$4.3
+cat $4.2 >> $4.3
+echo "debugfs -f $4.3"
+debugfs -f $4.3 > $4.4
+grep -v debugfs $4.4 > $4
+#rm $4.1
+#rm $4.2 
+#rm $4.3
+#rm $4.4
diff --git a/TBBT/trace_play/generate_xmgr b/TBBT/trace_play/generate_xmgr
new file mode 100755 (executable)
index 0000000..a44ed33
Binary files /dev/null and b/TBBT/trace_play/generate_xmgr differ
diff --git a/TBBT/trace_play/generate_xmgr.c b/TBBT/trace_play/generate_xmgr.c
new file mode 100644 (file)
index 0000000..354db18
--- /dev/null
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include "rfs_assert.h"
+
+#define EVEN_CHUNK_SIZE_MAX 2
+#define CHUNK_NUM_MAX 17
+#define FS_SIZE_MB_MAX 81
+#define STAGE_NUM_MAX 65
+typedef        struct {
+       int flag;
+       int frag_num;
+       int avg_frag_distance;
+       int avg_block_distance;
+} result_t;
+result_t result[EVEN_CHUNK_SIZE_MAX][CHUNK_NUM_MAX][FS_SIZE_MB_MAX][STAGE_NUM_MAX];
+
+int range_check (int i, int min, int max)
+{
+       if (i<min)
+               return 0;
+       if (i>max)
+               return 0;
+       return 1;
+}
+
+int file_ratio, active_ratio, chunk_num, fs_size_MB, even_chunk_size, stage_num;
+#define SEQ_NUM 11
+int frag_num[SEQ_NUM], td_MB[SEQ_NUM], td[SEQ_NUM], tblock_num[SEQ_NUM], file_num;
+main(int argc, char ** argv)
+{
+       char line[1024];
+       FILE * fp;
+       unsigned long long distance;
+       unsigned long long tll;
+       int avg_frag_distance = 0;
+       int max_blockno=0, avg_block_distance=0;
+       char * p;
+       int sequence[SEQ_NUM]={1,2,5,10,20,30,50,100,200,250,500};
+       int i;
+       char fhmap[1024];
+       result_t * resultp= NULL;
+
+
+       memset (result, 0, sizeof(result));
+
+       fp = fopen (argv[1], "r");
+       if (!fp) {
+               perror("open"); 
+               exit(-1);
+       }
+       i=-1;
+       while (fgets(line, sizeof(line), fp)) {
+               if (feof(fp))
+                       break;
+               if (strstr(line, "==>")) {
+                       RFS_ASSERT (resultp == NULL);
+
+                       p = strrchr (line, '/');
+                       if (p==NULL)
+                               p=line;
+                       p = strchr (p, '_');
+                       if (p==NULL) {
+                               printf("error 2\n");
+                               exit(-1);
+                       }
+                       sscanf (p, "_%d_%d_%d_%d_%d_%d_%s.5 <==\n", &even_chunk_size, &file_ratio, &active_ratio, &chunk_num, &fs_size_MB, &stage_num, fhmap);
+                       i = chunk_num;
+                       RFS_ASSERT (range_check (even_chunk_size, 0, EVEN_CHUNK_SIZE_MAX-1));
+                       RFS_ASSERT (range_check (chunk_num, 0, CHUNK_NUM_MAX-1));
+                       RFS_ASSERT (range_check (fs_size_MB/100, 0, FS_SIZE_MB_MAX-1));
+                       RFS_ASSERT (range_check (stage_num, 0, STAGE_NUM_MAX-1));
+                       resultp = & (result[even_chunk_size][chunk_num][fs_size_MB/100][stage_num]);
+                       RFS_ASSERT (resultp->flag == 0);
+               }
+               if (strstr(line, "****")) {
+
+                       RFS_ASSERT (resultp);
+
+                       sscanf(line, "****total FRAG_NUM %d td_MB %d td %d tblock_num %d max_blockno %d file_num %d avg_frag_distance %d avg_block_distance %d", &frag_num[0], &td_MB[0], &td[0],  &tblock_num[0], &max_blockno, &file_num, &avg_frag_distance, &avg_block_distance);
+                       sscanf(line, "****total FRAG_NUM %d td_MB %d td %d tblock_num %d max_blockno %d file_num %d avg_frag_distance %d avg_block_distance %d", &(resultp->frag_num), &td_MB[0], &td[0],  &tblock_num[0], &max_blockno, &file_num, &(resultp->avg_frag_distance), &(resultp->avg_block_distance));
+                       resultp ->flag = 1;
+
+                       //printf("%d %d %d %d %d %d\n", chunk_num, frag_num[0], avg_frag_distance, td_MB[0], tblock_num[0], avg_block_distance);
+
+                       resultp = NULL;
+               } 
+       }
+
+       print_xmgr ("avg_block_distance");
+       print_xmgr ("frag_num");
+       print_xmgr ("frag_size");
+       print_xmgr ("avg_frag_distance");
+       print_xmgr_chunk_stage ("avg_block_distance");
+}
+
+int print_y(FILE * fp, result_t * resultp, char * y_axis)
+{
+       if (!strcmp (y_axis, "avg_block_distance")) {
+               fprintf (fp, "%d ", resultp->avg_block_distance);
+       } else if (!strcmp (y_axis, "frag_num")) {
+               fprintf (fp, "%d ", resultp->frag_num);
+       } else if (!strcmp (y_axis, "frag_size")) {
+               fprintf (fp, "%f ", (float)tblock_num[0]/(float)resultp->frag_num);
+       } else if (!strcmp (y_axis, "avg_frag_distance")) {
+               fprintf (fp, "%d ", resultp->avg_frag_distance);
+       } else {
+               RFS_ASSERT (0);
+       }
+}
+       /* statistics for avg_block_distance */
+int print_xmgr (char * y_axis)
+{
+       int flag1, flag2;
+       result_t * resultp;
+       char name[1024];
+
+       FILE * fp = NULL;
+
+       for (even_chunk_size = 0; even_chunk_size < EVEN_CHUNK_SIZE_MAX; even_chunk_size ++) {
+               for (fs_size_MB = 0; fs_size_MB < FS_SIZE_MB_MAX; fs_size_MB ++) {
+
+                       sprintf (name, "xmgr.%d_%d.stage.%s", even_chunk_size, fs_size_MB*100, y_axis);
+                       fp = NULL;
+                       flag1 = 1;
+                       for (stage_num = 0; stage_num < STAGE_NUM_MAX; stage_num++) {
+                               flag2 = 1;
+                               for (chunk_num = 0; chunk_num < CHUNK_NUM_MAX; chunk_num++) {
+                                       resultp = &(result[even_chunk_size][chunk_num][fs_size_MB][stage_num]);
+                                       if (resultp->flag) {
+                                               if (flag1) {
+                                                       printf ("*** even %d fs_size_MB %d X: stage_num Y: %s Lines: different chunk_num ***\n", even_chunk_size, fs_size_MB*100, y_axis);
+                                                       flag1 = 0;
+                                                       if (!fp) {
+                                                               fp = fopen (name, "w");
+                                                               if (!fp)
+                                                                       RFS_ASSERT (0);
+                                                       }
+                                               }
+                                               if (flag2) {
+                                                       //fprintf (fp, "%d ", file_num/stage_num);
+                                                       fprintf (fp, "%f ", 1/((float)stage_num));
+                                                       flag2 = 0;
+                                               }
+                                               print_y (fp, resultp, y_axis);
+                                       }
+                               }
+                               if (!flag2)
+                                       fprintf (fp, "\n");
+                       }
+                       if (fp)
+                               fclose (fp);
+               }
+       }
+
+       for (even_chunk_size = 0; even_chunk_size < EVEN_CHUNK_SIZE_MAX; even_chunk_size ++) {
+               for (fs_size_MB = 0; fs_size_MB < FS_SIZE_MB_MAX; fs_size_MB ++) {
+                       sprintf (name, "xmgr.%d_%d.chunk.%s", even_chunk_size, fs_size_MB*100, y_axis);
+                       fp = NULL;
+                       flag1 = 1;
+                       for (chunk_num = 0; chunk_num < CHUNK_NUM_MAX; chunk_num++) {
+                               flag2 = 1;
+                               for (stage_num = 0; stage_num < STAGE_NUM_MAX; stage_num++) {
+                                       resultp = &(result[even_chunk_size][chunk_num][fs_size_MB][stage_num]);
+                                       if (resultp->flag) {
+                                               if (flag1) {
+                                                       printf ("*** even %d fs_size_MB %d X: chunk_num Y: %s Lines: different stage_num ***\n", even_chunk_size, fs_size_MB*100, y_axis);
+                                                       flag1 = 0;
+                                                       if (!fp) {
+                                                               fp = fopen (name, "w");
+                                                               if (!fp)
+                                                                       RFS_ASSERT (0);
+                                                       }
+                                               }
+                                               if (flag2) {
+                                                       fprintf (fp, "%d ", chunk_num);
+                                                       flag2 = 0;
+                                               }
+                                               print_y (fp, resultp, y_axis);
+                                       }
+                               }
+                               if (!flag2)
+                                       fprintf (fp, "\n");
+                       }
+                       if (fp)
+                               fclose (fp);
+               }
+       }
+}
+int print_xmgr_chunk_stage (char * y_axis)
+{
+       int flag1, flag2;
+       result_t * resultp;
+       char name[1024];
+
+       FILE * fp = NULL;
+
+       for (even_chunk_size = 0; even_chunk_size < EVEN_CHUNK_SIZE_MAX; even_chunk_size ++) {
+               for (fs_size_MB = 0; fs_size_MB < FS_SIZE_MB_MAX; fs_size_MB ++) {
+
+                       sprintf (name, "xmgr.%d_%d.stage_chunk.%s", even_chunk_size, fs_size_MB*100, y_axis);
+                       fp = NULL;
+                       flag1 = 1;
+                       for (stage_num = STAGE_NUM_MAX-1; stage_num>=0; stage_num--) {
+                               flag2 = 1;
+                               for (chunk_num = 0; chunk_num < CHUNK_NUM_MAX; chunk_num++) {
+                                       resultp = &(result[even_chunk_size][chunk_num][fs_size_MB][stage_num]);
+                                       if (resultp->flag) {
+                                               if (flag1) {
+                                                       printf ("*** even %d fs_size_MB %d X: stage_num Y: %s Lines: different chunk_num ***\n", even_chunk_size, fs_size_MB*100, y_axis);
+                                                       flag1 = 0;
+                                                       if (!fp) {
+                                                               fp = fopen (name, "w");
+                                                               if (!fp)
+                                                                       RFS_ASSERT (0);
+                                                       }
+                                               }
+                                               fprintf (fp, "%f ", chunk_num/((float)stage_num));
+                                               print_y (fp, resultp, y_axis);
+                                               fprintf (fp, "\n");
+                                       }
+                               }
+                       }
+                       if (fp)
+                               fclose (fp);
+               }
+       }
+}
diff --git a/TBBT/trace_play/generate_xmgr.c.old b/TBBT/trace_play/generate_xmgr.c.old
new file mode 100644 (file)
index 0000000..4a12ce2
--- /dev/null
@@ -0,0 +1,70 @@
+#include <stdio.h>
+main(int argc, char ** argv)
+{
+       char line[1024];
+       FILE * fp;
+       unsigned long long distance;
+       unsigned long long tll;
+       int avg_frag_distance = 0;
+#define SEQ_NUM 11
+       int frag_num[SEQ_NUM], td_MB[SEQ_NUM], td[SEQ_NUM], tblock_num[SEQ_NUM], file_num;
+       int max_blockno=0, avg_block_distance=0;
+       char * p;
+       int sequence[SEQ_NUM]={1,2,5,10,20,30,50,100,200,250,500};
+       int i;
+       int file_ratio, active_ratio, chunk_num, fs_size_MB;
+       char fhmap[1024];
+
+       fp = fopen (argv[1], "r");
+       if (!fp) {
+               perror("open"); 
+               exit(-1);
+       }
+       i=-1;
+       while (fgets(line, sizeof(line), fp)) {
+               if (feof(fp))
+                       break;
+               if (strstr(line, "==>")) {
+                       if (i!=-1) {
+                               printf("error 1\n");
+                               exit(-1);
+                       }
+                       p = strrchr (line, '/');
+                       if (p==NULL)
+                               p=line;
+                       p = strchr (p, '_');
+                       if (p==NULL) {
+                               printf("error 2\n");
+                               exit(-1);
+                       }
+                       sscanf (p, "_%d_%d_%d_%d_%s.5 <==\n", &file_ratio, &active_ratio, &chunk_num, &fs_size_MB, fhmap);
+                       i = chunk_num;
+               }
+               if (strstr(line, "****")) {
+                       if (i==-1) {
+                               printf("error 3\n");
+                               exit(-1);
+                       }
+                       sscanf(line, "****total FRAG_NUM %d td_MB %d td %d tblock_num %d max_blockno %d file_num %d avg_frag_distance %d avg_block_distance %d", &frag_num[0], &td_MB[0], &td[0],  &tblock_num[0], &max_blockno, &file_num, &avg_frag_distance, &avg_block_distance);
+
+#ifdef checkit
+                       distance = td_MB[0];
+                       distance *=1000000;
+                       distance +=td[0];
+                       tll = frag_num[0];
+                       distance /= frag_num[0];
+
+                       if (distance > 1000000000) {
+                               printf ("error 4\n");
+                               exit(-1);
+                       }
+                       avg_frag_distance = distance;
+                       printf("%d %d %d %d %d\n", chunk_num, frag_num[0], avg_frag_distance, td_MB[0], tblock_num[0]);
+#else
+                       printf("%d %d %d %d %d %d\n", chunk_num, frag_num[0], avg_frag_distance, td_MB[0], tblock_num[0], avg_block_distance);
+#endif
+                       i = -1;
+               } 
+       }
+}
+
diff --git a/TBBT/trace_play/generic_hash.c b/TBBT/trace_play/generic_hash.c
new file mode 100644 (file)
index 0000000..1d73a34
--- /dev/null
@@ -0,0 +1,230 @@
+/* generic_hash.c: Generic hash function that hashes on a maximum of three keys
+ * $Id: generic_hash.c,v 1.5 2002/08/21 22:08:01 ningning Exp $
+ * Changes:
+ * 
+ *     $Log: generic_hash.c,v $
+ *     Revision 1.5  2002/08/21 22:08:01  ningning
+ *     *** empty log message ***
+ *     
+ */
+
+#include <stdio.h>
+#include "generic_hash.h"
+
+/* create an entry for a block */
+void generic_insert(char * key1, unsigned int key1_size, unsigned int key3, struct generic_entry **htable, int hsize)
+{
+unsigned int index;
+struct generic_entry *p,*q;
+
+unsigned int * tmp =(unsigned int *)key1;
+unsigned int i;
+index = 0;
+for (i=0; i<(key1_size/4); i++) 
+       index += *(tmp+i);
+index = index%hsize;
+{
+//printf ("generic_insert index %d key %s\n", index, key1);
+}
+p = q = htable[index];
+while (p) {
+    if ((!memcmp(p->key1, key1, key1_size))
+        && (p->key3==key3)) {
+        return;
+    }
+    q = p;
+    p = p->next;
+}
+if (!p) {
+    p = (struct generic_entry *)malloc(sizeof(struct generic_entry));
+    memcpy(p->key1, key1, key1_size);
+    p->key3 = key3;
+    p->next = NULL;
+}
+if (!q)
+    htable[index] = p;
+else
+    q->next = p;
+return;
+}
+
+void generic_delete(char * key1, unsigned int key1_size, unsigned int key3, struct generic_entry **htable, int hsize)
+{
+unsigned int index;
+int found;
+struct generic_entry *p,*q;
+
+unsigned int * tmp =(unsigned int *)key1;
+unsigned int i;
+index = 0;
+for (i=0; i<(key1_size/4); i++) 
+       index += *(tmp+i);
+index = index%hsize;
+
+p = q = htable[index];
+found = 0;
+while (p) {
+    if ((!memcmp(p->key1, key1, key1_size)) 
+           && (p->key3==key3)) {
+               found = 1;
+               break;
+    }
+       q = p;
+    p = p->next;
+}
+RFS_ASSERT(found==1);
+if (p==htable[index])
+    htable[index] = p->next;
+else 
+    q->next = p->next;
+
+/* free hash entry */
+
+free(p);
+
+return;
+}
+
+struct generic_entry *generic_lookup(char * key1, unsigned int key1_size, unsigned int key3, struct generic_entry **htable, int hsize)
+{
+unsigned int index;
+struct generic_entry *p;
+
+unsigned int * tmp =(unsigned int *)key1;
+unsigned int i;
+index = 0;
+for (i=0; i<(key1_size/4); i++) 
+       index += *(tmp+i);
+index = index%hsize;
+{
+//printf ("generic_lookup index %d key %s\n", index, key1);
+}
+
+p = htable[index];
+while (p) {
+    if (!memcmp(p->key1, key1, key1_size)) 
+       {
+               return p;
+    }
+    p = p->next;
+}
+/*RFS_ASSERT(0);*/
+return NULL;
+}
+
+struct generic_entry *generic_lookup1(unsigned int key1, unsigned int key2, unsigned int key3, struct generic_entry **htable, int hsize)
+{
+unsigned int index;
+struct generic_entry *p;
+
+index = ((unsigned int)key1)%hsize;
+p = htable[index];
+while (p) {
+    if (p->key1==key1) 
+               return p;
+    p = p->next;
+}
+/*RFS_ASSERT(0);*/
+return NULL;
+}
+
+struct generic_entry *generic_lookup2(unsigned int key1, unsigned int key2, unsigned int key3, struct generic_entry **htable, int hsize)
+{
+unsigned int index;
+struct generic_entry *p;
+
+index = (key1 + key2)%hsize;
+p = htable[index];
+while (p) {
+    if (   (p->key1==key1) 
+           && (p->key2==key2)
+          )
+               return p;
+    p = p->next;
+}
+/*RFS_ASSERT(0);*/
+return NULL;
+}
+
+void generic_display(struct generic_entry **htable, int hsize, int numkeys)
+{
+int i;
+struct generic_entry *p;
+int counter = 0;
+
+for (i=0;i<hsize;i++) {
+    p = htable[i];
+       if (p) 
+               printf ("htable[%d]", i);
+    while (p) {
+               if (numkeys==1)
+                       printf("%d, ", p->key1);
+               else if (numkeys==2)
+                       printf("(%d,%x), ", p->key1,p->key2);
+               else 
+                       printf("(%d,%d,%d), ", p->key1,p->key2,p->key3);
+           p = p->next;
+        counter++;
+               if ((counter%4)==3) 
+                   printf("\n");
+    }
+}
+printf("\ncounter was %d\n",counter);
+}
+
+/* create an entry for a block */
+void generic_long_insert4(unsigned int key1, unsigned int key2, unsigned int key3, unsigned int key4, unsigned int key5, unsigned int key6, struct generic_long_entry **htable, int hsize)
+{
+int index;
+struct generic_long_entry *p,*q;
+
+index = (key1 + key2 + key3 + key4)%hsize;
+p = q = htable[index];
+while (p) {
+    if ((p->key1==key1) 
+           && (p->key2==key2)
+           && (p->key3==key3)
+           && (p->key4==key4)
+           && (p->key5==key5)
+           && (p->key6==key6)) {
+               return;
+    }
+       q = p;
+    p = p->next;
+}
+if (!p) {
+       p = (struct generic_long_entry *)malloc(sizeof(struct generic_long_entry));
+       p->key1 = key1;
+       p->key2 = key2;
+       p->key3 = key3;
+       p->key4 = key4;
+       p->key5 = key5;
+       p->key6 = key6;
+    p->next = NULL;
+}
+if (!q) 
+    htable[index] = p;
+else 
+    q->next = p;
+return;
+}
+
+struct generic_entry *generic_long_lookup4(unsigned int key1, unsigned int key2, unsigned int key3, unsigned int key4, struct generic_long_entry **htable, int hsize)
+{
+int index;
+struct generic_long_entry *p;
+
+index = (key1 + key2 + key3 + key4 )%hsize;
+p = htable[index];
+while (p) {
+    if (   (p->key1==key1) 
+           && (p->key2==key2)
+               && (p->key3==key3)
+               && (p->key4==key4)
+          )
+               return p;
+    p = p->next;
+}
+/*RFS_ASSERT(0);*/
+return NULL;
+}
diff --git a/TBBT/trace_play/generic_hash.h b/TBBT/trace_play/generic_hash.h
new file mode 100644 (file)
index 0000000..cf48bd4
--- /dev/null
@@ -0,0 +1,24 @@
+#include "rfs_c_def.h"
+struct generic_entry {
+       char key1[MAX_TRACE_FH_SIZE];
+    int key2;
+    int key3;
+    struct generic_entry *next;
+};
+
+struct generic_long_entry {
+    int key1;
+    int key2;
+    int key3;
+       int key4;
+       int key5;
+       int key6;
+    struct generic_long_entry *next;
+};
+
+void generic_insert(char * key1, unsigned int key2, unsigned int key3, struct generic_entry **htable, int hsize);
+void generic_delete(char * key1, unsigned int key2, unsigned int key3, struct generic_entry **htable, int hsize);
+struct generic_entry *generic_lookup(char * key1, unsigned int key2, unsigned int key3, struct generic_entry **htable, int hsize);
+
+void generic_display(struct generic_entry **htable, int hsize, int numkeys);
+
diff --git a/TBBT/trace_play/hash.h b/TBBT/trace_play/hash.h
new file mode 100644 (file)
index 0000000..808a95f
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef RFS_HASH_H
+#define RFS_HASH_H
+
+/* 
+ * hash.h: 
+ *             header file for routines to manipulate hash_tble lookup, 
+ *             insert and delete.
+ * 
+ * $Id: hash.h,v 1.1 2002/03/11 20:25:52 ningning Exp $
+ *
+ * Changes:
+ *             $Log: hash.h,v $
+ *             Revision 1.1  2002/03/11 20:25:52  ningning
+ *             hash function for file handle map completely implemented.
+ *             
+ */
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "../common/rfs_defines.h"
+#include "rfsu_defines.h"
+
+typedef struct rfsfh rfskey_t;
+
+struct hash_ent_struct {
+#ifdef HASH_DOUBLE_SAFE
+       struct timeval time;
+#endif
+       rfskey_t key;
+       int entry;
+       struct hash_ent_struct * next;
+};
+
+typedef struct hash_ent_struct hash_ent_t;
+
+typedef struct {
+       int size;
+       int used_entry; /* number of hash table entrie which contains valid data */
+       int valid_num;  /* number of valid data including those on the chain */
+       int (*hash_func) (rfskey_t * key, int size);    
+               /*  it's not C++ class, so we have to get size from outside */
+       hash_ent_t * buf;
+} hash_tbl_t;
+inline int hash_func1 (rfskey_t * key, int size);
+inline int blk_hash_func (blkkey_t * key, int size);
+int hash_tbl_init (hash_tbl_t * hash_tbl);
+int hash_tbl_insert (hash_tbl_t * hash_tbl, rfskey_t * key, int entry, int mode);
+int hash_tbl_delete (hash_tbl_t * hash_tbl, rfskey_t * key);
+int hash_tbl_lookup (hash_tbl_t * hash_tbl, rfskey_t * key);
+
+#ifdef ULFS
+
+struct blk_hash_ent_struct {
+#ifdef HASH_DOUBLE_SAFE
+       struct timeval time;
+#endif
+       blkkey_t key;
+       int entry;
+       struct blk_hash_ent_struct * next;
+};
+
+typedef struct blk_hash_ent_struct blk_hash_ent_t;
+
+typedef struct {
+       int size;
+       int keysize;
+       int entsize;
+       int quiet_flag;
+       int used_entry; /* number of hash table entrie which contains valid data */
+       int valid_num;  /* number of valid data including those on the chain */
+       int (*hash_func) (blkkey_t * key, int size);    
+               /*  it's not C++ class, so we have to get size from outside */
+       blk_hash_ent_t * buf;
+} blk_hash_tbl_t;
+
+int blk_hash_tbl_init (blk_hash_tbl_t * hash_tbl);
+int blk_hash_tbl_insert (blk_hash_tbl_t * hash_tbl, blkkey_t * key, int entry, int mode);
+//int blk_hash_tbl_delete (blk_hash_tbl_t * hash_tbl, blkkey_t * key);
+int blk_hash_tbl_lookup (blk_hash_tbl_t * hash_tbl, blkkey_t * key);
+
+#endif
+
+#endif
diff --git a/TBBT/trace_play/init_holder.c b/TBBT/trace_play/init_holder.c
new file mode 100644 (file)
index 0000000..f12d683
--- /dev/null
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define FILE_NUM 25000
+#define DIR_NUM 1
+#define FILE_SIZE 40960
+
+int print_usage()
+{
+       printf("init_holder DIR_NUM HOLDER_NUM HOLDER_SIZE testdir\n");
+}
+
+main4(int argc, char ** argv)
+{
+       int i, j;
+       char name[256];
+       char cmd[1024];
+       char buf[FILE_SIZE];
+       int fd, ret;
+       char testdir[1024];
+
+       if (argc!=5) {
+               print_usage();
+               exit (-1);
+       }
+       if (DIR_NUM !=1) {
+               for (i=0; i<DIR_NUM; i++) {
+                       memset (name, 0, sizeof(name));
+                       sprintf(name, "%s/%d", testdir, i);
+                       ret = mkdir (name, S_IRWXU);
+                       if (ret == -1) {
+                               perror(name);
+                               exit(-1);
+                       }
+               }
+       }
+
+       for (j=0; j<DIR_NUM; j++) {
+               for (i=0; i<FILE_NUM/DIR_NUM; i++) {
+                       if (DIR_NUM == 1)  
+                               sprintf(name, "%s/%d", testdir, i);
+                       else
+                               sprintf(name, "%s/%d/%d", testdir, j, i);
+                       fd = open (name, O_CREAT|O_WRONLY);
+                       if (fd == -1) {
+                               perror(name);
+                               exit(-1);
+                       }
+                       ret = write (fd, buf, FILE_SIZE );
+                       close (fd);
+                       if (ret!=FILE_SIZE) {
+                               printf("try to write %d , get %d\n", SIZE, ret);
+                               exit (-1);
+                       }
+               }
+       }
+}
diff --git a/TBBT/trace_play/nfsd_nfsfh_cust.h b/TBBT/trace_play/nfsd_nfsfh_cust.h
new file mode 100644 (file)
index 0000000..942dc92
--- /dev/null
@@ -0,0 +1,114 @@
+#define __u32 unsigned int
+#define u32 unsigned int
+#define __u16 unsigned short
+#define u16 unsigned short
+#define __u64 unsigned long long
+#define u64 unsigned long long
+#define __u8 unsigned char
+#define u8 unsigned char
+#define __s64 signed long long
+
+struct nfs_fhbase_old {
+       __u32           fb_dcookie;     /* dentry cookie - always 0xfeebbaca */
+       __u32           fb_ino;         /* our inode number */
+       __u32           fb_dirino;      /* dir inode number, 0 for directories */
+       __u32           fb_dev;         /* our device */
+       __u32           fb_xdev;
+       __u32           fb_xino;
+       __u32           fb_generation;
+};
+
+/*
+ * This is the new flexible, extensible style NFSv2/v3 file handle.
+ * by Neil Brown <neilb@cse.unsw.edu.au> - March 2000
+ *
+ * The file handle is seens as a list of 4byte words.
+ * The first word contains a version number (1) and four descriptor bytes
+ * that tell how the remaining 3 variable length fields should be handled.
+ * These three bytes are auth_type, fsid_type and fileid_type.
+ *
+ * All 4byte values are in host-byte-order.
+ *
+ * The auth_type field specifies how the filehandle can be authenticated
+ * This might allow a file to be confirmed to be in a writable part of a
+ * filetree without checking the path from it upto the root.
+ * Current values:
+ *     0  - No authentication.  fb_auth is 0 bytes long
+ * Possible future values:
+ *     1  - 4 bytes taken from MD5 hash of the remainer of the file handle
+ *          prefixed by a secret and with the important export flags.
+ *
+ * The fsid_type identifies how the filesystem (or export point) is
+ *    encoded.
+ *  Current values:
+ *     0  - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
+ *        NOTE: we cannot use the kdev_t device id value, because kdev_t.h
+ *              says we mustn't.  We must break it up and reassemble.
+ *  Possible future encodings:
+ *     1  - 4 byte user specified identifier
+ *
+ * The fileid_type identified how the file within the filesystem is encoded.
+ * This is (will be) passed to, and set by, the underlying filesystem if it supports
+ * filehandle operations.  The filesystem must not use the value '0' or '0xff' and may
+ * only use the values 1 and 2 as defined below:
+ *  Current values:
+ *    0   - The root, or export point, of the filesystem.  fb_fileid is 0 bytes.
+ *    1   - 32bit inode number, 32 bit generation number.
+ *    2   - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number.
+ *
+ */
+struct nfs_fhbase_new {
+       __u8            fb_version;     /* == 1, even => nfs_fhbase_old */
+       __u8            fb_auth_type;
+       __u8            fb_fsid_type;
+       __u8            fb_fileid_type;
+#ifndef RFS
+       __u32           fb_auth[1];
+/*     __u32           fb_fsid[0]; floating */
+/*     __u32           fb_fileid[0]; floating */
+#else
+       __u16           fb_dev_major;
+       __u16           fb_dev_minor;
+       __u32           fb_dev_ino;
+       __u32           fb_ino;
+       __u32           fb_generation;
+       __u32           fb_dirino;
+#endif
+       
+};
+
+// RFS struct knfsd_fh {                       
+struct knfs_fh {                                                                                               // RFS
+       unsigned int    fh_size;        /* significant for NFSv3.
+                                        * Points to the current size while building
+                                        * a new file handle
+                                        */
+       union {
+               struct nfs_fhbase_old   fh_old;
+               __u32                   fh_pad[NFS3_FHSIZE/4];
+               struct nfs_fhbase_new   fh_new;
+       } fh_base;
+};
+
+#define ofh_dcookie            fh_base.fh_old.fb_dcookie
+#define ofh_ino                        fh_base.fh_old.fb_ino
+#define ofh_dirino             fh_base.fh_old.fb_dirino
+#define ofh_dev                        fh_base.fh_old.fb_dev
+#define ofh_xdev               fh_base.fh_old.fb_xdev
+#define ofh_xino               fh_base.fh_old.fb_xino
+#define ofh_generation         fh_base.fh_old.fb_generation
+
+#define        fh_version              fh_base.fh_new.fb_version
+#define        fh_fsid_type            fh_base.fh_new.fb_fsid_type
+#define        fh_auth_type            fh_base.fh_new.fb_auth_type
+#define        fh_fileid_type          fh_base.fh_new.fb_fileid_type
+#define        fh_auth                 fh_base.fh_new.fb_auth
+
+// RFS
+#define fh_dev_major   fh_base.fh_new.fb_dev_major
+#define fh_dev_minor   fh_base.fh_new.fb_dev_minor
+#define fh_dev_ino             fh_base.fh_new.fb_dev_ino
+#define fh_ino                 fh_base.fh_new.fb_ino
+#define fh_generation  fh_base.fh_new.fb_generation
+#define fh_dirino              fh_base.fh_new.fb_dirino
+
diff --git a/TBBT/trace_play/profile.c b/TBBT/trace_play/profile.c
new file mode 100755 (executable)
index 0000000..23548c1
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * profile.c
+ *
+ * $Id: profile.c,v 1.1 2002/08/21 22:08:01 ningning Exp $
+ * Changes:
+ *     $Log: profile.c,v $
+ *     Revision 1.1  2002/08/21 22:08:01  ningning
+ *     *** empty log message ***
+ *     
+ */
+
+#include <sys/time.h>
+#include <sys/sem.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "profile.h"
+#include "rfs_assert.h"
+//#include "rfs_c_def.h"
+extern FILE * profile_fp;
+
+static struct timezone tz;
+inline void calculate_interval 
+       (struct timeval * ts, struct timeval * te, struct timeval * interval)
+{
+       if (te->tv_usec < ts->tv_usec) {
+               if (te->tv_sec <= ts->tv_sec) {
+                       printf ("te->tv_sec %d ts->tv_sec %d\n", te->tv_sec, ts->tv_sec);
+                       printf ("te->tv_usec %d ts->tv_usec %d\n", te->tv_usec, ts->tv_usec);
+               }
+               RFS_ASSERT (te->tv_sec > ts->tv_sec);
+               te->tv_usec += 1000000;
+               te->tv_sec -= 1;
+       }
+
+       interval->tv_sec  = te->tv_sec - ts->tv_sec;
+       interval->tv_usec = te->tv_usec - ts->tv_usec;
+       if (interval->tv_usec > 1000000) {
+               if (interval->tv_usec > 2000000) {
+                       printf ("interval->tv_sec %d interval->tv_usec %d \n", interval->tv_sec, interval->tv_usec);
+                       printf ("ts->tv_sec %d ts->tv_usec %d \n", ts->tv_sec, ts->tv_usec);
+                       printf ("te->tv_sec %d te->tv_usec %d \n", te->tv_sec, te->tv_usec);
+               }
+               /* Sometimes it can happend that te->tv_usec > 1000000 */
+               interval->tv_sec += 1;
+               interval->tv_usec -= 1000000;
+               RFS_ASSERT (interval->tv_usec < 1000000);
+       }
+}
+
+inline void normalize_profile (int pos, struct timeval * time)
+{
+       if (!(time->tv_sec >=0 && time->tv_usec >=0 && time->tv_usec < 2000000)) {
+               printf ("pos %d tv_sec %d tv_usec %d\n", pos, time->tv_sec, time->tv_usec);
+       };
+       RFS_ASSERT (time->tv_sec >=0 && time->tv_usec >=0 && time->tv_usec < 2000000);
+       while (time->tv_usec >= 1000000) {
+               time->tv_usec -= 1000000;
+               time->tv_sec += 1;
+       }
+}
+
+inline void start_real_profile (profile_t * profile)
+{
+       start_profile(profile);
+}
+
+inline void end_real_profile (profile_t * profile)
+{
+       end_profile(profile);
+}
+
+inline void start_profile (profile_t * profile)
+{
+/*
+       if (strlen(profile->about) < 3) {
+               printf ("total_profile address: %x %x\n", &total_profile, profile);
+       }
+*/
+
+       gettimeofday(&(profile->ts), &tz);
+       normalize_profile (1, &(profile->ts));
+}
+
+inline void end_profile (profile_t * profile)
+{
+       struct timeval te, teorg;
+       struct timeval * ts; 
+       struct timeval * in;
+       struct timeval oldin;
+       
+/*
+       //printf ("end_profile %s\n", profile->about);
+
+       if (strlen(profile->about) < 3) {
+               printf ("total_profile address: %x %x\n", &total_profile, profile);
+       }
+*/
+
+       oldin = profile->in;
+       in = &(profile->in);
+       ts = &(profile->ts);
+
+       gettimeofday(&te, &tz);
+       normalize_profile (2, &te);
+       teorg = te;
+
+       RFS_ASSERT (te.tv_sec >= ts->tv_sec);
+       RFS_ASSERT (te.tv_usec >=0 && ts->tv_usec >=0);
+       while (te.tv_usec < ts->tv_usec) {
+               if (te.tv_sec <= ts->tv_sec) {
+                       printf ("%s ts.tv_sec %d ts.tv_usec %d\n", profile->about, ts->tv_sec, ts->tv_usec);
+                       printf ("teorg.tv_sec %d teorg.tv_usec %d\n", teorg.tv_sec, teorg.tv_usec);
+               }
+               RFS_ASSERT (te.tv_sec > ts->tv_sec);
+               te.tv_usec += 1000000;
+               te.tv_sec -= 1;
+       }
+
+       if (!(in->tv_sec >=0 && in->tv_usec >=0)) {
+               printf ("in->tv_sec %d, in->tv_usec %d\n", in->tv_sec, in->tv_usec);
+       };
+       RFS_ASSERT (in->tv_sec >=0 && in->tv_usec >=0);
+       in->tv_sec  += te.tv_sec - ts->tv_sec;
+       in->tv_usec += te.tv_usec - ts->tv_usec;
+       normalize_profile (3, in);
+
+       if (!(in->tv_sec >=0 && in->tv_sec <864000)) {
+                printf (" ts.tv_sec %d ts.tv_usec %d\n", ts->tv_sec, ts->tv_usec);
+                printf (" te.tv_sec %d te.tv_usec %d\n", te.tv_sec, te.tv_usec);
+                printf (" in.tv_sec %d in.tv_usec %d\n", in->tv_sec, in->tv_usec);
+                printf (" oldin.tv_sec %d oldin.tv_usec %d\n", oldin.tv_sec, oldin.tv_usec);
+       }
+
+       profile->num ++;
+       profile->ts = teorg;
+}
+
+inline void init_profile (char * string, profile_t * profile)
+{
+       RFS_ASSERT (strlen(string) < sizeof (profile->about));
+       memset (profile, 0, sizeof(profile_t));
+       strcpy (profile->about, string);
+}
+
+inline int calculate_avg_timeval (struct timeval * in, int num)
+{
+       unsigned long long i;
+       int ret;
+
+       if (in->tv_sec < 2000) {
+               return ((in->tv_sec*1000000+in->tv_usec)/num );
+       } else {
+               i = ((unsigned long long)in->tv_sec)*1000000 + in->tv_usec;
+               i/= num;
+               RFS_ASSERT (i<2000000000);
+               ret = i;
+               return ret;
+       }
+}
+
+inline void print_profile (char * string, profile_t * profile)
+{
+       struct timeval * ts = &(profile->ts);
+       struct timeval * in = &(profile->in);
+
+/*
+       if (strcmp (string, profile->about)) {
+               printf ("print_profile string %s about %s\n", string, profile->about);
+       }
+*/
+
+       //RFS_ASSERT (!strcmp (string, profile->about));
+       if (in->tv_usec<0 || in->tv_usec>1000000) {
+               printf ("%s in->tv_usec %d, in->tv_sec %d num %d\n", profile->about, in->tv_usec, in->tv_sec, profile->num);
+       }
+
+       RFS_ASSERT (in->tv_usec>=0 && in->tv_usec<1000000);
+       
+       if (!(in->tv_sec >=0 && in->tv_sec <864000)) {
+                printf ("%s ts.tv_sec %d ts.tv_usec %d\n", profile->about, ts->tv_sec, ts->tv_usec);
+                printf ("%s in.tv_sec %d in.tv_usec %d\n", profile->about, in->tv_sec, in->tv_usec);
+       }
+       RFS_ASSERT (in->tv_sec >=0 && in->tv_sec <864000);      /* it's about 10 days */
+
+       if (profile->num == 0) {
+               printf("... %40s %3d.%06d num %d \n", profile->about, in->tv_sec, in->tv_usec, 
+                       profile->num);
+
+               if (profile_fp) {
+                       fprintf(profile_fp, "... %40s %3d.%06d num %d \n", profile->about, in->tv_sec,
+                               in->tv_usec, profile->num );
+                       //perror("print_profile_1");
+               }
+       } else {
+
+               int avg = calculate_avg_timeval (in, profile->num);
+               printf("... %40s %3d.%06d num %d avg %d \n", profile->about, in->tv_sec, in->tv_usec, 
+                       profile->num, avg);
+
+               if (profile_fp) {
+                       fprintf(profile_fp, "... %40s %3d.%06d num %d avg %d \n", profile->about, in->tv_sec,
+                               in->tv_usec, profile->num, avg);
+               }
+
+/*
+               printf("... %40s %3d.%06d num %d avg %d \n", string, in->tv_sec, in->tv_usec, 
+                       profile->num, (in->tv_sec*1000000+in->tv_usec)/profile->num );
+
+               if (profile_fp) {
+                       fprintf(profile_fp, "... %40s %3d.%06d num %d avg %d \n", string, in->tv_sec,
+                               in->tv_usec, profile->num, (in->tv_sec*1000000+in->tv_usec)/profile->num );
+               }
+*/
+       }
+}
diff --git a/TBBT/trace_play/profile.h b/TBBT/trace_play/profile.h
new file mode 100755 (executable)
index 0000000..606652e
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef PROFILE_H
+#define PROFILE_H
+
+/* profile.h: header file for profiling routine
+ * $Id: profile.h,v 1.2 2002/08/21 22:11:40 ningning Exp $
+ * Changes:
+ *
+ *     $Log: profile.h,v $
+ *     Revision 1.2  2002/08/21 22:11:40  ningning
+ *     *** empty log message ***
+ *     
+ */
+
+#include <sys/time.h>
+#define MAX_PROFILE_ABOUT_LEN 128
+typedef struct {
+    struct timeval ts;
+    struct timeval in;
+    int num;
+    char about[MAX_PROFILE_ABOUT_LEN];
+} profile_t;
+                                                                                                                                   
+extern inline void start_profile (profile_t * profile);
+extern inline void end_profile (profile_t * profile);
+extern inline void print_profile (char * string, profile_t * profile);
+extern inline void init_profile (char * string, profile_t * profile);
+#endif
diff --git a/TBBT/trace_play/rfs_3_ops.c b/TBBT/trace_play/rfs_3_ops.c
new file mode 100644 (file)
index 0000000..f91bf05
--- /dev/null
@@ -0,0 +1,827 @@
+#ifndef lint
+static char sfs_3_opsSid[] = "@(#)sfs_3_ops.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include "sfs_c_def.h"
+#include "rfs_c_def.h"
+
+#define TRY_SETARG_FAST
+#define TRY_SETRES_FAST
+extern fh_map_t * lookup_fh (char * trace_fh);
+extern void print_result(void);
+
+char * lookup_fhandle(char * fhandle)
+{
+       fh_map_t * fh;
+       fh = lookup_fh(fhandle);
+       RFS_ASSERT (fh);
+       return ((char *)&fh->play_fh);
+}
+
+
+#define setarg_fhandle(fhp) \
+       fh_map_t * fh; \
+       t = strstr (line, "fh");        \
+       RFS_ASSERT (t);                         \
+       t += 3;                                         \
+       fh = lookup_fh(t);                      \
+       RFS_ASSERT (fh);                        \
+       (void) memmove((char *)fhp, &(fh->play_fh),                     \
+                                                                      sizeof (nfs_fh3));       \
+       t+=TRACE_FH_SIZE+1;
+       //t = strchr (t, ' '); t++; \
+
+void setarg_getattr (int index, char * line, GETATTR3args * args)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+#else
+       setarg_fhandle(&args->object);
+#endif
+}
+
+struct ladtime * adjust_time (struct timeval tm, int * sec, int * usec)
+{
+       struct ladtime trace_pkt_time;
+       static struct ladtime trace_arg_time;
+       struct timeval curtmp;
+       struct ladtime cur;
+
+       /* not sure whether sec ==0 means anything special, do not adjust the timestamp for this */
+       if (*sec ==0) {
+               RFS_ASSERT (0);
+               RFS_ASSERT (*usec == 0);
+               trace_arg_time.sec = 0;
+               trace_arg_time.usec = 0;
+               return (&trace_arg_time);
+       }
+       trace_pkt_time.sec = tm.tv_sec;
+       trace_pkt_time.usec = tm.tv_usec;
+
+       trace_arg_time.sec = *sec;
+       trace_arg_time.usec = *usec;
+
+       gettimeofday(&curtmp, NULL);
+       cur.sec = curtmp.tv_sec;
+       cur.usec = curtmp.tv_usec;
+
+       //fprintf (stderr, "trace_pkt_time %d.%d trace_arg_time %d.%d cur %d.%d\n", trace_pkt_time.sec, trace_pkt_time.usec, trace_arg_time.sec, trace_arg_time.usec, cur.sec, cur.usec);
+
+       ADDTIME (trace_arg_time, cur);
+       //fprintf(stderr, "after add, %d.%d\n", trace_arg_time.sec, trace_arg_time.usec);
+       RFS_ASSERT (LARGERTIME (trace_arg_time, trace_pkt_time));
+       SUBTIME (trace_arg_time, trace_pkt_time);
+       return (&trace_arg_time);
+}
+
+char * parse_create_mode(char * t, createmode3 * mode)
+{
+       *mode = UNCHECKED;
+       return (t+2);
+       /* anyway, we can not get concrete result from the trace, just chose this mode */
+       RFS_ASSERT (0);
+}
+
+char * parse_sattr3(char * t, sattr3 * args, sattrguard3 * guard, int index)
+{
+       int i,j;
+       struct ladtime * tm;
+
+       /* set the default value of SETATTR3args->*/
+    args->mode.set_it = FALSE;
+    args->uid.set_it = FALSE;
+    args->gid.set_it = FALSE;
+    args->size.set_it = FALSE;
+    args->atime.set_it = FALSE;
+    args->mtime.set_it = FALSE;
+
+       //fprintf(stderr, "parse_sattr: line %s\n", t);
+       while (1) {
+               if (!strncmp (t, "mode", 4)) {
+                       t+=5;
+                       sscanf(t, "%x", &i); 
+                       args->mode.set_it = TRUE;
+                       args->mode.mode = i;            // (uint32_t) 0666;
+               } else if (!strncmp (t, "ctime", 5)) {
+                       RFS_ASSERT (guard);
+                       t+=6;
+                       RFS_ASSERT (strncmp(t, "SERVER", 6));
+                       sscanf (t, "%d.%d", &i, &j);
+                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+#ifndef IGNORE_SETATTR_CTIME
+                       guard->check = TRUE;
+#endif
+                       guard->obj_ctime.seconds = tm->sec;
+                       guard->obj_ctime.nseconds = tm->usec*1000;
+               } else if (!strncmp (t, "atime", 5)) {
+                       t+=6;
+                       if (!strncmp(t, "SERVER", 6)) {
+                               args->atime.set_it = SET_TO_SERVER_TIME;
+                       } else {
+                               args->atime.set_it = SET_TO_CLIENT_TIME;
+                               sscanf (t, "%d.%d", &i, &j);
+                               if (i==0) {
+                                       RFS_ASSERT (j==0);
+                                       args->atime.atime.seconds = 0;
+                                       args->atime.atime.nseconds = 0;
+                               } else {
+                                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+                                       args->atime.atime.seconds = tm->sec;
+                                       args->atime.atime.nseconds = tm->usec * 1000;
+                               }
+                       }
+               } else if (!strncmp (t, "mtime", 5)) {
+                       t+=6;
+                       if (!strncmp(t, "SERVER", 6)) {
+                               args->mtime.set_it = SET_TO_SERVER_TIME;
+                       } else {
+                               args->mtime.set_it = SET_TO_CLIENT_TIME;
+                               sscanf (t, "%d.%d", &i, &j);
+                               if (i==0) {
+                                       RFS_ASSERT (j==0);
+                                       args->mtime.mtime.seconds = 0;
+                                       args->mtime.mtime.nseconds = 0;
+                               } else {
+                                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+                                       args->mtime.set_it = TRUE;
+                                       args->mtime.mtime.seconds = tm->sec;
+                                       args->mtime.mtime.nseconds = tm->usec * 1000;
+                               }
+                       }
+               } else if (!strncmp (t, "size", 4)) {
+                               t+=5;
+                       sscanf(t, "%x", &i); 
+                       args->size.set_it = TRUE;
+                       args->size.size._p._u = (uint32_t) 0;
+                       args->size.size._p._l = (uint32_t) i;
+               } else if (!strncmp (t, "gid", 3)) {
+                       t+=4;
+                       sscanf(t, "%x", &i); 
+                       args->gid.set_it = TRUE;
+#ifdef TAKE_CARE_SETATTR_GID
+                       args->gid.gid = i;
+#else
+                       args->gid.gid = 513;
+#endif
+               } else if ( !strncmp (t, "uid", 3)) {
+                       t+=4;
+                       sscanf(t, "%x", &i); 
+                       args->uid.set_it = TRUE;
+#ifdef TAKE_CARE_SETATTR_UID
+                       args->uid.uid = i;
+#else
+                       args->uid.uid = 513;
+#endif
+               } else if (!strncmp (t, "con", 3)) {
+                       break;
+               } else if (!strncmp (t, "sdata", 5)) {
+                       break;
+               } else {
+                       fprintf(stderr, "parse_sattr t: %s\n", t);
+                       RFS_ASSERT (0);
+               }
+
+               while (*t!=' ')
+                       t++;
+               t++;
+       }
+       return t;
+}
+
+char * parse_name (char * t, char * buf)
+{
+       int i;
+       if (!strncmp(t, "fn2", 3))
+               t+=4;
+       else if (!strncmp(t, "fn", 2))
+               t+=3;
+       else if (!strncmp(t, "name2", 5))
+               t+=6;
+       else if (!strncmp(t, "name", 4))
+               t+=5;
+       else if (!strncmp(t, "sdata", 5))
+               t+=6;
+       else {
+               fprintf(stderr, "%s\n", t);
+               RFS_ASSERT (0);
+       }
+
+       RFS_ASSERT (*t=='"');
+       t++;
+       i = 0;
+       while (*t!='"')
+               buf[i++] = *t++; // ??? name buffer?    
+       RFS_ASSERT ((*t)=='"');
+       buf[i] = 0;
+       return (t+2);
+}
+
+char * parse_access_mode (char * line, int * mode)
+{
+       *mode = ACCESS3_READ;   
+       return line+2;
+       /* anyway the information in the trace is not enough, so we just make up something */
+}
+
+char * parse_stable_mode (char * line, stable_how * mode)
+{
+       switch (*line) {
+       case 'U': *mode = UNSTABLE;
+                         break;
+       case 'F': *mode = FILE_SYNC;
+                         break;
+       case 'D': *mode = DATA_SYNC;
+                         break;
+       default:
+               RFS_ASSERT (0);
+       }
+       return line +2;
+}
+
+
+void setarg_setattr (int index, char * line, SETATTR3args * args)
+{
+       char * t;
+       int i, j;
+       
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->object);
+#endif
+
+       args->guard.check = FALSE;
+       t = parse_sattr3 (t, &(args->new_attributes), &(args->guard), index);
+}
+
+void setarg_lookup (int index, char * line, LOOKUP3args * args, char * Cur_filename)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->what.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->what.dir)
+#endif
+       t = parse_name (t, Cur_filename);
+       args->what.name = Cur_filename;
+}
+
+void setarg_access (int index, char * line, ACCESS3args * args)
+{
+       char * t;
+
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->object);
+#endif
+
+       parse_access_mode (t, &args->access);   //ACCESS3_MODIFY;       // ??? the actual parameter can be different
+}
+
+void setarg_readlink (int index, char * line, READLINK3args * args)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->symlink, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->symlink);
+#endif
+}
+
+void setarg_read (int index, char * line, READ3args * args, char * buf)
+{
+       char * t;
+       int i;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->file, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->file);
+#endif
+
+       if (line[TRACE_VERSION_POS]=='3') {
+               t = strstr (t, "off");
+               RFS_ASSERT (t);
+               t+=4;
+       } else {
+               t = strstr (t, "offset");
+               RFS_ASSERT (t);
+               t+=7;
+       }
+       sscanf (t, "%x", &i);
+
+       RFS_ASSERT (i>=0 && i<0x7FFFFFFF)
+       args->offset._p._u = 0;
+       args->offset._p._l = i;
+#ifdef SEQUEN_READ
+       if (index>=memory_trace_index.head)
+               args->offset._p._l = (index-memory_trace_index.head)*4096;
+#endif
+       t = strstr (t, "count");
+       RFS_ASSERT (t);
+       t+=6;
+       sscanf (t, "%x", &i);
+
+       RFS_ASSERT (i <= 32768);
+       if (i > NFS_MAXDATA) {
+               read_data_owe += (i-NFS_MAXDATA);
+               read_data_adjust_times ++;
+               if (read_data_owe > 1073741824) {
+                       read_data_owe -= 1073741824;
+                       read_data_owe_GB ++;
+               }
+               
+               //printf ("adjust read count from %d to %d\n", i, NFS_MAXDATA);
+               i = NFS_MAXDATA;
+       }
+       read_data_total += i;
+       if (read_data_total > 1073741824) {
+               read_data_total -= 1073741824;
+               read_data_total_GB ++;
+       }
+
+       args->count = i;
+}
+
+void setarg_write (int index, char * line, WRITE3args * args, char * buf)
+{
+       char * t;
+       int i;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->file, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->file);
+#endif
+
+       //fprintf (stderr, "process write: %s\n", line);
+       if (line[TRACE_VERSION_POS]=='3') {
+               t = strstr (t, "off");
+               RFS_ASSERT (t);
+               t+=4;
+       } else {
+               RFS_ASSERT (line[TRACE_VERSION_POS]=='2');
+               t = strstr (t, "offset");
+               RFS_ASSERT (t);
+               t+=7;
+       }
+
+       sscanf (t, "%x", &i);
+       RFS_ASSERT (i>=0 && i<0x7FFFFFFF)
+       args->offset._p._u = 0;
+       args->offset._p._l = i;
+
+       t = strstr (t, "count");
+       RFS_ASSERT (t);
+       t+=6;
+       sscanf (t, "%x", &i);
+       RFS_ASSERT (i <= 32768);
+       if (i > NFS_MAXDATA) {
+               write_data_owe += (i-NFS_MAXDATA);
+               if (write_data_owe > 1073741824) {
+                       write_data_owe -= 1073741824;
+                       write_data_owe_GB ++;
+               }
+               write_data_adjust_times ++;
+               //printf ("adjust write count from %d to %d\n", i, NFS_MAXDATA);
+               i = NFS_MAXDATA;
+       }
+       write_data_total += i;
+       if (write_data_total > 1073741824) {
+               write_data_total -= 1073741824;
+               write_data_total_GB ++;
+       }
+
+       RFS_ASSERT (i < MAX_BUF1_SIZE-128);     /* 128 is some random safe number to add */
+       args->count = i;
+
+       if (line[TRACE_VERSION_POS]==3) {
+               t = strstr (t, "stable");
+               RFS_ASSERT (t);
+               t+=7;
+               parse_stable_mode(t, &args->stable);    /* *t can be F, U, etc */ 
+       } else
+               args->stable = UNSTABLE;
+       args->data.data_len = args->count;
+       args->data.data_val = buf;
+}
+
+void setarg_create (int index, char * line, CREATE3args * args, char * Cur_filename)
+{
+       char * t;
+       //fprintf(stderr, "process create %s\n", line);
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->where.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->where.dir);
+#endif
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       if (line[TRACE_VERSION_POS]=='3') {
+               RFS_ASSERT (!strncmp(t, "how", 3));
+               t+=4;
+       t = parse_create_mode (t, &args->how.mode);
+       } else
+               args->how.mode = UNCHECKED;
+       t = parse_sattr3 (t, &(args->how.createhow3_u.obj_attributes), NULL, index);
+}
+
+void setarg_mkdir (int index, char * line, MKDIR3args * args, char * Cur_filename)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->where.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->where.dir);
+#endif
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       t = parse_sattr3 (t, &(args->attributes), NULL, index);
+}
+
+void setarg_symlink(int index, char * line, SYMLINK3args * args, char * Cur_filename, char * sym_data)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->where.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle (&args->where.dir);
+#endif
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       if (line[TRACE_VERSION_POS]=='2') {
+               t = parse_name (t, sym_data);
+               t = parse_sattr3 (t, &(args->symlink.symlink_attributes), NULL, index);
+       } else {
+               t = parse_sattr3 (t, &(args->symlink.symlink_attributes), NULL, index);
+               t = parse_name (t, sym_data);
+       }
+    args->symlink.symlink_data = sym_data;
+}
+
+void setarg_mknod(int index, char * line, MKNOD3args * args, char * Cur_filename)
+{
+       RFS_ASSERT (0);
+
+#ifdef notdef
+       /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.what.type = NF3FIFO;
+    args.what.mknoddata3_u.pipe_attributes.mode.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mode.mode = (NFSMODE_FIFO | 0777);
+    args.what.mknoddata3_u.pipe_attributes.uid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.uid.uid = Cur_uid;
+    args.what.mknoddata3_u.pipe_attributes.gid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.gid.gid = Cur_gid;
+    args.what.mknoddata3_u.pipe_attributes.size.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._u = (uint32_t) 0;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._l =
+                                                       (uint32_t) 512;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+    args.what.mknoddata3_u.pipe_attributes.mtime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.seconds =
+                                                               Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+#endif
+}
+
+void setarg_remove (int index, char * line, REMOVE3args * args, char * Cur_filename)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->object.dir)
+#endif
+       t = parse_name (t, Cur_filename);
+       args->object.name = Cur_filename;
+}
+
+void setarg_rmdir (int index, char * line, RMDIR3args * args, char * Cur_filename)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object.dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->object.dir)
+#endif
+       t = parse_name (t, Cur_filename);
+       args->object.name = Cur_filename;
+}
+
+void setarg_rename (int index, char * line, RENAME3args * args, char * fromname, char * toname)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->from.dir, &dep_tab[index].fh_2->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh_2 + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh_2, ' '); t++; 
+#else
+       setarg_fhandle(&args->from.dir)
+#endif
+       t = parse_name (t, fromname);
+       args->from.name = fromname;
+
+       t = strstr (t, "fh2");  
+       RFS_ASSERT (t);                         
+       t += 4;                                         
+       memmove((char *)&args->to.dir, lookup_fhandle(t), sizeof (nfs_fh3));    
+       t+=65;
+
+       t = parse_name (t, toname);
+       args->to.name = toname;
+}
+
+void setarg_link (int index, char * line, LINK3args * args, char * Cur_filename)
+{
+       char * t;
+
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->file, &dep_tab[index].fh_2->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh_2 + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh_2, ' '); t++; 
+#else
+       setarg_fhandle(&args->file)
+#endif
+
+       t = strstr (t, "fh2");  
+       RFS_ASSERT (t);                         
+       t += 4;                                         
+       memmove((char *)&args->link.dir, lookup_fhandle(t), sizeof (nfs_fh3));  
+       t+=65;
+
+       t = parse_name (t, Cur_filename);
+       args->link.name = Cur_filename;
+}
+
+void  setarg_readdir (int index, char * line, READDIR3args * args)
+{
+       char * t;
+
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->dir);
+#endif
+       /* args->cookieverf is notset, it is not implemented in the linux-2.4.7 */
+       sscanf(t, "cookie %d count %d", &args->cookie._p._l, &args->count);
+    (void) memset((char *) args->cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args->cookie._p._u = (uint32_t) 0;
+}
+
+void  setarg_readdirplus (int index, char * line, READDIRPLUS3args * args)
+{
+       char * t;
+
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->dir, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->dir);
+#endif
+       /* args->cookieverf is notset, it is not implemented in the linux-2.4.7 */
+       sscanf(t, "cookie %d count %d maxcnt", &args->cookie._p._l, &args->dircount, &args->maxcount);
+    (void) memset((char *) args->cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args->cookie._p._u = (uint32_t) 0;
+
+#ifdef notdef
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args.dircount = DEFAULT_MAX_BUFSIZE;
+       args.maxcount = DEFAULT_MAX_BUFSIZE;
+#endif
+}
+
+void setarg_fsstat (int index, char * line, FSSTAT3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->fsroot);
+}
+
+void setarg_fsinfo (int index, char * line, FSINFO3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->fsroot);
+}
+
+void setarg_pathconf (int index, char * line, PATHCONF3args * args)
+{
+       char * t;
+#ifdef TRY_SETARG_FAST
+       memcpy (&args->object, &dep_tab[index].fh->play_fh, sizeof(nfs_fh3));
+       //t = dep_tab[index].trace_fh + TRACE_FH_SIZE+1;
+       t = strchr(dep_tab[index].trace_fh, ' '); t++; 
+#else
+       setarg_fhandle(&args->object);
+#endif
+}
+
+void setarg_commit (int index, char * line, COMMIT3args * args)
+{
+       RFS_ASSERT (0);
+
+#ifdef notdef
+       /* set up the arguments */
+       (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+                  sizeof (nfs_fh3));
+       args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+       args.count = Cur_file_ptr->attributes3.size._p._l;
+#endif
+}
+
+void setbuf_void (char * buf)
+{
+       return;
+}
+
+void setbuf_invalid (char * buf)
+{
+       RFS_ASSERT (0);
+}
+
+void setres_lookup (LOOKUP3res * reply)
+{
+#ifndef TRY_SETRES_FAST
+    (void) memset((char *) &(reply->resok.object), '\0', sizeof (nfs_fh3));
+#endif
+}
+
+void setres_readlink (READLINK3res * reply, char * sym_data)
+{
+    /* Have lower layers fill in the data directly. */
+    reply->resok.data = sym_data;
+}
+
+void setres_read (READ3res * reply, char * buf)
+{
+       /* Have lower layers fill in the data directly.  */
+       reply->resok.data.data_len = 0;
+       reply->resok.data.data_val = buf;
+}
+
+void setres_readdir (READDIR3res * reply, entry3 * entry_stream)
+{
+#ifndef TRY_SETRES_FAST
+    /* Have lower layers fill in the data directly.  */
+    (void) memset((char *) reply, '\0', sizeof (READDIR3res));
+    (void) memset((char *) entry_stream, '\0',
+                                       sizeof (entry3) * SFS_MAXDIRENTS);
+#endif
+    reply->resok.count = SFS_MAXDIRENTS;
+    reply->resok.reply.entries = entry_stream;
+}
+
+void setres_readdirplus (READDIRPLUS3res * reply, entryplus3 * entry_stream)
+{
+#ifndef TRY_SETRES_FAST
+    (void) memset((char *) reply, '\0', sizeof (READDIRPLUS3res));
+       //printf ("sizeof(entryplus3) %d SFS_MAXDIRENT %d\n", sizeof (entryplus3), SFS_MAXDIRENTS);
+    (void) memset((char *) entry_stream, '\0',
+                               sizeof (entryplus3) * SFS_MAXDIRENTS);
+#endif
+    reply->resok.count = SFS_MAXDIRENTS;
+    reply->resok.reply.entries = entry_stream;
+}
+
+#define NFSPROC3_INVALID -1
+/* the array is indexed by sfs operation number */
+rfs_op_type rfs_Ops[TOTAL] = {
+{NFSPROC3_NULL,                setbuf_void,            setbuf_void, xdr_void, xdr_void},
+{NFSPROC3_GETATTR,     setarg_getattr,         setbuf_void, xdr_GETATTR3args, xdr_GETATTR3res},
+{NFSPROC3_SETATTR,     setarg_setattr,         setbuf_void, xdr_SETATTR3args, xdr_SETATTR3res},
+{NFSPROC3_INVALID,     setbuf_invalid,         setbuf_invalid, NULL, NULL},
+{NFSPROC3_LOOKUP,      setarg_lookup,          setres_lookup, xdr_LOOKUP3args, xdr_LOOKUP3res},
+{NFSPROC3_READLINK, setarg_readlink,   setres_readlink, xdr_READLINK3args, xdr_READLINK3res},
+{NFSPROC3_READ,        setarg_read,            setres_read, xdr_READ3args, xdr_READ3res},
+{NFSPROC3_INVALID,     setbuf_invalid,         setbuf_invalid, NULL, NULL},
+{NFSPROC3_WRITE,       setarg_write,           setbuf_void, xdr_WRITE3args, xdr_WRITE3res},
+{NFSPROC3_CREATE,      setarg_create,          setbuf_void, xdr_CREATE3args, xdr_CREATE3res},
+{NFSPROC3_REMOVE,      setarg_remove,          setbuf_void, xdr_REMOVE3args, xdr_REMOVE3res},
+{NFSPROC3_RENAME,      setarg_rename,          setbuf_void, xdr_RENAME3args, xdr_RENAME3res},
+{NFSPROC3_LINK,        setarg_link,            setbuf_void, xdr_LINK3args, xdr_LINK3res},
+{NFSPROC3_SYMLINK,     setarg_symlink,         setbuf_void, xdr_SYMLINK3args, xdr_SYMLINK3res},
+{NFSPROC3_MKDIR,       setarg_mkdir,           setbuf_void, xdr_MKDIR3args, xdr_MKDIR3res},
+{NFSPROC3_RMDIR,       setarg_rmdir,           setbuf_void, xdr_RMDIR3args, xdr_RMDIR3res},
+{NFSPROC3_READDIR,     setarg_readdir,         setres_readdir, xdr_READDIR3args, xdr_READDIR3res},
+{NFSPROC3_FSSTAT,      setarg_fsstat,          setbuf_void, xdr_FSSTAT3args, xdr_FSSTAT3res},
+{NFSPROC3_ACCESS,      setarg_access,          setbuf_void, xdr_ACCESS3args, xdr_ACCESS3res},
+{NFSPROC3_COMMIT,      setarg_commit,          setbuf_void, xdr_COMMIT3args, xdr_COMMIT3res},
+{NFSPROC3_FSINFO,      setarg_fsinfo,          setbuf_void,  xdr_FSINFO3args, xdr_FSINFO3res},
+{NFSPROC3_MKNOD,       setarg_mknod,           setbuf_void, xdr_MKNOD3args, xdr_MKNOD3res},
+{NFSPROC3_PATHCONF, setarg_pathconf,   setbuf_void, xdr_PATHCONF3args, xdr_PATHCONF3res},
+{NFSPROC3_READDIRPLUS, setarg_readdirplus, setres_readdirplus, xdr_READDIRPLUS3args, xdr_READDIRPLUS3res}};
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+sfs_op_type nfsv3_Ops[] = {
+
+/* name        mix    op    call  no  req  req  req  results */
+/*             pcnt  class  targ call pcnt cnt  targ         */
+
+ { "null",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    11, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     27, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       18, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       9, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     2, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",      7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",      5, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",    0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 9, Read,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+
+sfs_op_type *Ops;
+
diff --git a/TBBT/trace_play/rfs_3_ops.c.old b/TBBT/trace_play/rfs_3_ops.c.old
new file mode 100644 (file)
index 0000000..37a47be
--- /dev/null
@@ -0,0 +1,739 @@
+#ifndef lint
+static char sfs_3_opsSid[] = "@(#)sfs_3_ops.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include "sfs_c_def.h"
+#include "rfs_c_def.h"
+
+extern fh_map_t * lookup_fh (char * trace_fh);
+
+char * lookup_fhandle(char * fhandle)
+{
+       fh_map_t * fh;
+       fh = lookup_fh(fhandle);
+       RFS_ASSERT (fh);
+       return ((char *)&fh->play_fh);
+}
+
+
+#define setarg_fhandle(fhp) \
+       fh_map_t * fh; \
+       t = strstr (line, "fh");        \
+       RFS_ASSERT (t);                         \
+       t += 3;                                         \
+       fh = lookup_fh(t);                      \
+       RFS_ASSERT (fh);                        \
+       (void) memmove((char *)fhp, &(fh->play_fh),                     \
+                                                                      sizeof (nfs_fh3));       \
+       t+=TRACE_FH_SIZE+1;
+
+void setarg_getattr (int index, char * line, GETATTR3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->object);
+}
+
+struct ladtime * adjust_time (struct timeval tm, int * sec, int * usec)
+{
+       struct ladtime trace_pkt_time;
+       static struct ladtime trace_arg_time;
+       struct timeval curtmp;
+       struct ladtime cur;
+
+       /* not sure whether sec ==0 means anything special, do not adjust the timestamp for this */
+       if (*sec ==0) {
+               RFS_ASSERT (0);
+               RFS_ASSERT (*usec == 0);
+               trace_arg_time.sec = 0;
+               trace_arg_time.usec = 0;
+               return (&trace_arg_time);
+       }
+       trace_pkt_time.sec = tm.tv_sec;
+       trace_pkt_time.usec = tm.tv_usec;
+
+       trace_arg_time.sec = *sec;
+       trace_arg_time.usec = *usec;
+
+       gettimeofday(&curtmp, NULL);
+       cur.sec = curtmp.tv_sec;
+       cur.usec = curtmp.tv_usec;
+
+       //fprintf (stderr, "trace_pkt_time %d.%d trace_arg_time %d.%d cur %d.%d\n", trace_pkt_time.sec, trace_pkt_time.usec, trace_arg_time.sec, trace_arg_time.usec, cur.sec, cur.usec);
+
+       ADDTIME (trace_arg_time, cur);
+       //fprintf(stderr, "after add, %d.%d\n", trace_arg_time.sec, trace_arg_time.usec);
+       RFS_ASSERT (LARGERTIME (trace_arg_time, trace_pkt_time));
+       SUBTIME (trace_arg_time, trace_pkt_time);
+       return (&trace_arg_time);
+}
+
+char * parse_create_mode(char * t, createmode3 * mode)
+{
+       *mode = UNCHECKED;
+       return (t+2);
+       /* anyway, we can not get concrete result from the trace, just chose this mode */
+       RFS_ASSERT (0);
+}
+
+char * parse_sattr3(char * t, sattr3 * args, sattrguard3 * guard, int index)
+{
+       int i,j;
+       struct ladtime * tm;
+
+       /* set the default value of SETATTR3args->*/
+    args->mode.set_it = FALSE;
+    args->uid.set_it = FALSE;
+    args->gid.set_it = FALSE;
+    args->size.set_it = FALSE;
+    args->atime.set_it = FALSE;
+    args->mtime.set_it = FALSE;
+
+       //fprintf(stderr, "parse_sattr: line %s\n", t);
+       while (1) {
+               if (!strncmp (t, "mode", 4)) {
+                       t+=5;
+                       sscanf(t, "%x", &i); 
+                       args->mode.set_it = TRUE;
+                       args->mode.mode = i;            // (uint32_t) 0666;
+               } else if (!strncmp (t, "ctime", 5)) {
+                       RFS_ASSERT (guard);
+                       t+=6;
+                       RFS_ASSERT (strncmp(t, "SERVER", 6));
+                       sscanf (t, "%d.%d", &i, &j);
+                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+#ifndef IGNORE_SETATTR_CTIME
+                       guard->check = TRUE;
+#endif
+                       guard->obj_ctime.seconds = tm->sec;
+                       guard->obj_ctime.nseconds = tm->usec*1000;
+               } else if (!strncmp (t, "atime", 5)) {
+                       t+=6;
+                       if (!strncmp(t, "SERVER", 6)) {
+                               args->atime.set_it = SET_TO_SERVER_TIME;
+                       } else {
+                               args->atime.set_it = SET_TO_CLIENT_TIME;
+                               sscanf (t, "%d.%d", &i, &j);
+                               if (i==0) {
+                                       RFS_ASSERT (j==0);
+                                       args->atime.atime.seconds = 0;
+                                       args->atime.atime.nseconds = 0;
+                               } else {
+                                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+                                       args->atime.atime.seconds = tm->sec;
+                                       args->atime.atime.nseconds = tm->usec * 1000;
+                               }
+                       }
+               } else if (!strncmp (t, "mtime", 5)) {
+                       t+=6;
+                       if (!strncmp(t, "SERVER", 6)) {
+                               args->mtime.set_it = SET_TO_SERVER_TIME;
+                       } else {
+                               args->mtime.set_it = SET_TO_CLIENT_TIME;
+                               sscanf (t, "%d.%d", &i, &j);
+                               if (i==0) {
+                                       RFS_ASSERT (j==0);
+                                       args->mtime.mtime.seconds = 0;
+                                       args->mtime.mtime.nseconds = 0;
+                               } else {
+                                       tm = adjust_time (dep_tab[index].timestamp, &i, &j);
+                                       args->mtime.set_it = TRUE;
+                                       args->mtime.mtime.seconds = tm->sec;
+                                       args->mtime.mtime.nseconds = tm->usec * 1000;
+                               }
+                       }
+               } else if (!strncmp (t, "size", 4)) {
+                               t+=5;
+                       sscanf(t, "%x", &i); 
+                       args->size.set_it = TRUE;
+                       args->size.size._p._u = (uint32_t) 0;
+                       args->size.size._p._l = (uint32_t) i;
+               } else if (!strncmp (t, "gid", 3)) {
+                       t+=4;
+                       sscanf(t, "%x", &i); 
+                       args->gid.set_it = TRUE;
+#ifdef TAKE_CARE_SETATTR_GID
+                       args->gid.gid = i;
+#else
+                       args->gid.gid = 513;
+#endif
+               } else if ( !strncmp (t, "uid", 3)) {
+                       t+=4;
+                       sscanf(t, "%x", &i); 
+                       args->uid.set_it = TRUE;
+#ifdef TAKE_CARE_SETATTR_UID
+                       args->uid.uid = i;
+#else
+                       args->uid.uid = 513;
+#endif
+               } else if (!strncmp (t, "con", 3)) {
+                       break;
+               } else if (!strncmp (t, "sdata", 5)) {
+                       break;
+               } else {
+                       fprintf(stderr, "parse_sattr t: %s\n", t);
+                       RFS_ASSERT (0);
+               }
+
+               while (*t!=' ')
+                       t++;
+               t++;
+       }
+       return t;
+}
+
+char * parse_name (char * t, char * buf)
+{
+       int i;
+       if (!strncmp(t, "fn2", 3))
+               t+=4;
+       else if (!strncmp(t, "fn", 2))
+               t+=3;
+       else if (!strncmp(t, "name2", 5))
+               t+=6;
+       else if (!strncmp(t, "name", 4))
+               t+=5;
+       else if (!strncmp(t, "sdata", 5))
+               t+=6;
+       else {
+               fprintf(stderr, "%s\n", t);
+               RFS_ASSERT (0);
+       }
+
+       RFS_ASSERT (*t=='"');
+       t++;
+       i = 0;
+       while (*t!='"')
+               buf[i++] = *t++; // ??? name buffer?    
+       RFS_ASSERT ((*t)=='"');
+       buf[i] = 0;
+       return (t+2);
+}
+
+char * parse_access_mode (char * line, int * mode)
+{
+       *mode = ACCESS3_READ;   
+       return line+2;
+       /* anyway the information in the trace is not enough, so we just make up something */
+}
+
+char * parse_stable_mode (char * line, stable_how * mode)
+{
+       switch (*line) {
+       case 'U': *mode = UNSTABLE;
+                         break;
+       case 'F': *mode = FILE_SYNC;
+                         break;
+       case 'D': *mode = DATA_SYNC;
+                         break;
+       default:
+               RFS_ASSERT (0);
+       }
+       return line +2;
+}
+
+
+void setarg_setattr (int index, char * line, SETATTR3args * args)
+{
+       char * t;
+       int i, j;
+       
+       setarg_fhandle(&args->object);
+       args->guard.check = FALSE;
+       t = parse_sattr3 (t, &(args->new_attributes), &(args->guard), index);
+}
+
+void setarg_lookup (int index, char * line, LOOKUP3args * args, char * Cur_filename)
+{
+       char * t;
+       setarg_fhandle(&args->what.dir)
+       t = parse_name (t, Cur_filename);
+       args->what.name = Cur_filename;
+}
+
+void setarg_access (int index, char * line, ACCESS3args * args)
+{
+       char * t;
+
+       setarg_fhandle (&args->object);
+       parse_access_mode (t, &args->access);   //ACCESS3_MODIFY;       // ??? the actual parameter can be different
+}
+
+void setarg_readlink (int index, char * line, READLINK3args * args)
+{
+       char * t;
+       setarg_fhandle (&args->symlink);
+}
+
+void setarg_read (int index, char * line, READ3args * args, char * buf)
+{
+       char * t;
+       int i;
+       setarg_fhandle (&args->file);
+
+       if (line[TRACE_VERSION_POS]=='3') {
+               t = strstr (t, "off");
+               RFS_ASSERT (t);
+               t+=4;
+       } else {
+               t = strstr (t, "offset");
+               RFS_ASSERT (t);
+               t+=7;
+       }
+       sscanf (t, "%x", &i);
+
+       RFS_ASSERT (i>=0 && i<0x7FFFFFFF)
+       args->offset._p._u = 0;
+       args->offset._p._l = i;
+       t = strstr (t, "count");
+       RFS_ASSERT (t);
+       t+=6;
+       sscanf (t, "%x", &i);
+
+       RFS_ASSERT (i <= 32768);
+       if (i > NFS_MAXDATA) {
+               read_data_owe += (i-NFS_MAXDATA);
+               read_data_adjust_times ++;
+               if (read_data_owe > 1073741824) {
+                       read_data_owe -= 1073741824;
+                       read_data_owe_GB ++;
+               }
+               
+               //printf ("adjust read count from %d to %d\n", i, NFS_MAXDATA);
+               i = NFS_MAXDATA;
+       }
+       read_data_total += i;
+       RFS_ASSERT (read_data_total <1073741824);
+
+       args->count = i;
+}
+
+void setarg_write (int index, char * line, WRITE3args * args, char * buf)
+{
+       char * t;
+       int i;
+       setarg_fhandle (&args->file);
+
+       //fprintf (stderr, "process write: %s\n", line);
+       if (line[TRACE_VERSION_POS]=='3') {
+               t = strstr (t, "off");
+               RFS_ASSERT (t);
+               t+=4;
+       } else {
+               RFS_ASSERT (line[TRACE_VERSION_POS]=='2');
+               t = strstr (t, "offset");
+               RFS_ASSERT (t);
+               t+=7;
+       }
+
+       sscanf (t, "%x", &i);
+       RFS_ASSERT (i>=0 && i<0x7FFFFFFF)
+       args->offset._p._u = 0;
+       args->offset._p._l = i;
+
+       t = strstr (t, "count");
+       RFS_ASSERT (t);
+       t+=6;
+       sscanf (t, "%x", &i);
+       RFS_ASSERT (i <= 32768);
+       if (i > NFS_MAXDATA) {
+               write_data_owe += (i-NFS_MAXDATA);
+               if (write_data_owe > 1073741824) {
+                       write_data_owe -= 1073741824;
+                       write_data_owe_GB ++;
+               }
+               write_data_adjust_times ++;
+               //printf ("adjust write count from %d to %d\n", i, NFS_MAXDATA);
+               i = NFS_MAXDATA;
+       }
+       write_data_total += i;
+       RFS_ASSERT (write_data_total <1073741824);
+
+       RFS_ASSERT (i < MAX_BUF1_SIZE-128);     /* 128 is some random safe number to add */
+       args->count = i;
+
+       if (line[TRACE_VERSION_POS]==3) {
+               t = strstr (t, "stable");
+               RFS_ASSERT (t);
+               t+=7;
+               parse_stable_mode(t, &args->stable);    /* *t can be F, U, etc */ 
+       } else
+               args->stable = UNSTABLE;
+       args->data.data_len = args->count;
+       args->data.data_val = buf;
+}
+
+void setarg_create (int index, char * line, CREATE3args * args, char * Cur_filename)
+{
+       char * t;
+       //fprintf(stderr, "process create %s\n", line);
+       setarg_fhandle (&args->where.dir);
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       if (line[TRACE_VERSION_POS]=='3') {
+               RFS_ASSERT (!strncmp(t, "how", 3));
+               t+=4;
+       t = parse_create_mode (t, &args->how.mode);
+       } else
+               args->how.mode = UNCHECKED;
+       t = parse_sattr3 (t, &(args->how.createhow3_u.obj_attributes), NULL, index);
+}
+
+void setarg_create_old (int index, char * line, CREATE3args * retargs, char * Cur_filename)
+{
+       CREATE3args args;
+
+       sprintf(Cur_filename, "%d", index);
+       if (rfs_debug)
+               printf ("create file %s\n", Cur_filename);
+
+    /* set up the arguments */
+    (void) memmove((char *)&args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename; //RFS need a buffer for the name 
+    args.how.mode = UNCHECKED;
+    args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
+    args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+    args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+    args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.atime.atime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.size.size._p._u = (uint32_t) 0;
+    args.how.createhow3_u.obj_attributes.size.size._p._l = (uint32_t) 0;
+
+       memcpy (retargs, &args, sizeof (CREATE3args));
+}
+
+void setarg_mkdir (int index, char * line, MKDIR3args * args, char * Cur_filename)
+{
+       char * t;
+       setarg_fhandle (&args->where.dir);
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       t = parse_sattr3 (t, &(args->attributes), NULL, index);
+}
+
+void setarg_symlink(int index, char * line, SYMLINK3args * args, char * Cur_filename, char * sym_data)
+{
+       char * t;
+       setarg_fhandle (&args->where.dir);
+       t = parse_name (t, Cur_filename);
+       args->where.name = Cur_filename;
+       if (line[TRACE_VERSION_POS]=='2') {
+               t = parse_name (t, sym_data);
+               t = parse_sattr3 (t, &(args->symlink.symlink_attributes), NULL, index);
+       } else {
+               t = parse_sattr3 (t, &(args->symlink.symlink_attributes), NULL, index);
+               t = parse_name (t, sym_data);
+       }
+    args->symlink.symlink_data = sym_data;
+}
+
+void setarg_mknod(int index, char * line, MKNOD3args * args, char * Cur_filename)
+{
+       RFS_ASSERT (0);
+
+#ifdef notdef
+       /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.what.type = NF3FIFO;
+    args.what.mknoddata3_u.pipe_attributes.mode.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mode.mode = (NFSMODE_FIFO | 0777);
+    args.what.mknoddata3_u.pipe_attributes.uid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.uid.uid = Cur_uid;
+    args.what.mknoddata3_u.pipe_attributes.gid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.gid.gid = Cur_gid;
+    args.what.mknoddata3_u.pipe_attributes.size.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._u = (uint32_t) 0;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._l =
+                                                       (uint32_t) 512;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+    args.what.mknoddata3_u.pipe_attributes.mtime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.seconds =
+                                                               Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+#endif
+}
+
+void setarg_remove (int index, char * line, REMOVE3args * args, char * Cur_filename)
+{
+       char * t;
+       setarg_fhandle(&args->object.dir)
+       t = parse_name (t, Cur_filename);
+       args->object.name = Cur_filename;
+}
+
+void setarg_rmdir (int index, char * line, RMDIR3args * args, char * Cur_filename)
+{
+       char * t;
+       setarg_fhandle(&args->object.dir)
+       t = parse_name (t, Cur_filename);
+       args->object.name = Cur_filename;
+}
+
+void setarg_rename (int index, char * line, RENAME3args * args, char * fromname, char * toname)
+{
+       char * t;
+       setarg_fhandle(&args->from.dir)
+       t = parse_name (t, fromname);
+       args->from.name = fromname;
+
+       t = strstr (t, "fh2");  
+       RFS_ASSERT (t);                         
+       t += 4;                                         
+       memmove((char *)&args->to.dir, lookup_fhandle(t), sizeof (nfs_fh3));    
+       t+=65;
+
+       t = parse_name (t, toname);
+       args->to.name = toname;
+}
+
+void setarg_link (int index, char * line, LINK3args * args, char * Cur_filename)
+{
+       char * t;
+
+       setarg_fhandle(&args->file)
+
+       t = strstr (t, "fh2");  
+       RFS_ASSERT (t);                         
+       t += 4;                                         
+       memmove((char *)&args->link.dir, lookup_fhandle(t), sizeof (nfs_fh3));  
+       t+=65;
+
+       t = parse_name (t, Cur_filename);
+       args->link.name = Cur_filename;
+}
+
+void  setarg_readdir (int index, char * line, READDIR3args * args)
+{
+       char * t;
+
+       setarg_fhandle(&args->dir);
+       /* args->cookieverf is notset, it is not implemented in the linux-2.4.7 */
+       sscanf(t, "cookie %d count %d", &args->cookie._p._l, &args->count);
+    (void) memset((char *) args->cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args->cookie._p._u = (uint32_t) 0;
+}
+
+void  setarg_readdirplus (int index, char * line, READDIRPLUS3args * args)
+{
+       char * t;
+
+       setarg_fhandle(&args->dir);
+       /* args->cookieverf is notset, it is not implemented in the linux-2.4.7 */
+       sscanf(t, "cookie %d count %d maxcnt", &args->cookie._p._l, &args->dircount, &args->maxcount);
+    (void) memset((char *) args->cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args->cookie._p._u = (uint32_t) 0;
+
+#ifdef notdef
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+       args.dircount = DEFAULT_MAX_BUFSIZE;
+       args.maxcount = DEFAULT_MAX_BUFSIZE;
+#endif
+}
+
+void setarg_fsstat (int index, char * line, FSSTAT3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->fsroot);
+}
+
+void setarg_fsinfo (int index, char * line, FSINFO3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->fsroot);
+}
+
+void setarg_pathconf (int index, char * line, PATHCONF3args * args)
+{
+       char * t;
+       setarg_fhandle(&args->object);
+}
+
+void setarg_commit (int index, char * line, COMMIT3args * args)
+{
+       RFS_ASSERT (0);
+
+#ifdef notdef
+       /* set up the arguments */
+       (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+                  sizeof (nfs_fh3));
+       args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+       args.count = Cur_file_ptr->attributes3.size._p._l;
+#endif
+}
+
+void setbuf_void (char * buf)
+{
+       return;
+}
+
+void setbuf_invalid (char * buf)
+{
+       RFS_ASSERT (0);
+}
+
+void setres_lookup (LOOKUP3res * reply)
+{
+    (void) memset((char *) &(reply->resok.object), '\0', sizeof (nfs_fh3));
+}
+
+void setres_readlink (READLINK3res * reply, char * sym_data)
+{
+    /* Have lower layers fill in the data directly. */
+    reply->resok.data = sym_data;
+}
+
+void setres_read (READ3res * reply, char * buf)
+{
+       /* Have lower layers fill in the data directly.  */
+       reply->resok.data.data_len = 0;
+       reply->resok.data.data_val = buf;
+}
+
+void setres_readdir (READDIR3res * reply, entry3 * entry_stream)
+{
+    /* Have lower layers fill in the data directly.  */
+    (void) memset((char *) reply, '\0', sizeof (READDIR3res));
+    (void) memset((char *) entry_stream, '\0',
+                                       sizeof (entry3) * SFS_MAXDIRENTS);
+    reply->resok.count = SFS_MAXDIRENTS;
+    reply->resok.reply.entries = entry_stream;
+}
+
+void setres_readdirplus (READDIRPLUS3res * reply, entryplus3 * entry_stream)
+{
+    (void) memset((char *) reply, '\0', sizeof (READDIRPLUS3res));
+       //printf ("sizeof(entryplus3) %d SFS_MAXDIRENT %d\n", sizeof (entryplus3), SFS_MAXDIRENTS);
+    (void) memset((char *) entry_stream, '\0',
+                               sizeof (entryplus3) * SFS_MAXDIRENTS);
+    reply->resok.count = SFS_MAXDIRENTS;
+    reply->resok.reply.entries = entry_stream;
+}
+
+#define NFSPROC3_INVALID -1
+/* the array is indexed by sfs operation number */
+rfs_op_type rfs_Ops[TOTAL] = {
+{NFSPROC3_NULL,                setbuf_void,            setbuf_void, xdr_void, xdr_void},
+{NFSPROC3_GETATTR,     setarg_getattr,         setbuf_void, xdr_GETATTR3args, xdr_GETATTR3res},
+{NFSPROC3_SETATTR,     setarg_setattr,         setbuf_void, xdr_SETATTR3args, xdr_SETATTR3res},
+{NFSPROC3_INVALID,     setbuf_invalid,         setbuf_invalid, NULL, NULL},
+{NFSPROC3_LOOKUP,      setarg_lookup,          setres_lookup, xdr_LOOKUP3args, xdr_LOOKUP3res},
+{NFSPROC3_READLINK, setarg_readlink,   setres_readlink, xdr_READLINK3args, xdr_READLINK3res},
+{NFSPROC3_READ,        setarg_read,            setres_read, xdr_READ3args, xdr_READ3res},
+{NFSPROC3_INVALID,     setbuf_invalid,         setbuf_invalid, NULL, NULL},
+{NFSPROC3_WRITE,       setarg_write,           setbuf_void, xdr_WRITE3args, xdr_WRITE3res},
+{NFSPROC3_CREATE,      setarg_create,          setbuf_void, xdr_CREATE3args, xdr_CREATE3res},
+{NFSPROC3_REMOVE,      setarg_remove,          setbuf_void, xdr_REMOVE3args, xdr_REMOVE3res},
+{NFSPROC3_RENAME,      setarg_rename,          setbuf_void, xdr_RENAME3args, xdr_RENAME3res},
+{NFSPROC3_LINK,        setarg_link,            setbuf_void, xdr_LINK3args, xdr_LINK3res},
+{NFSPROC3_SYMLINK,     setarg_symlink,         setbuf_void, xdr_SYMLINK3args, xdr_SYMLINK3res},
+{NFSPROC3_MKDIR,       setarg_mkdir,           setbuf_void, xdr_MKDIR3args, xdr_MKDIR3res},
+{NFSPROC3_RMDIR,       setarg_rmdir,           setbuf_void, xdr_RMDIR3args, xdr_RMDIR3res},
+{NFSPROC3_READDIR,     setarg_readdir,         setres_readdir, xdr_READDIR3args, xdr_READDIR3res},
+{NFSPROC3_FSSTAT,      setarg_fsstat,          setbuf_void, xdr_FSSTAT3args, xdr_FSSTAT3res},
+{NFSPROC3_ACCESS,      setarg_access,          setbuf_void, xdr_ACCESS3args, xdr_ACCESS3res},
+{NFSPROC3_COMMIT,      setarg_commit,          setbuf_void, xdr_COMMIT3args, xdr_COMMIT3res},
+{NFSPROC3_FSINFO,      setarg_fsinfo,          setbuf_void,  xdr_FSINFO3args, xdr_FSINFO3res},
+{NFSPROC3_MKNOD,       setarg_mknod,           setbuf_void, xdr_MKNOD3args, xdr_MKNOD3res},
+{NFSPROC3_PATHCONF, setarg_pathconf,   setbuf_void, xdr_PATHCONF3args, xdr_PATHCONF3res},
+{NFSPROC3_READDIRPLUS, setarg_readdirplus, setres_readdirplus, xdr_READDIRPLUS3args, xdr_READDIRPLUS3res}};
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+sfs_op_type nfsv3_Ops[] = {
+
+/* name        mix    op    call  no  req  req  req  results */
+/*             pcnt  class  targ call pcnt cnt  targ         */
+
+ { "null",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    11, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     27, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       18, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       9, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     2, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",      7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",      5, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",    0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 9, Read,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+
+sfs_op_type *Ops;
+
diff --git a/TBBT/trace_play/rfs_assert.h b/TBBT/trace_play/rfs_assert.h
new file mode 100644 (file)
index 0000000..ec360d5
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef RFS_ASSERT_H
+#define RFS_ASSERT_H
+#define RFS_ASSERT(condition)                                       \
+    if (!(condition)) {                                             \
+        fprintf(stderr, "Assertion failed: line %d, file \"%s\"\n", \
+                           __LINE__, __FILE__);                        \
+               fflush(stdout); \
+               fflush(stdout); \
+               fflush(stderr); \
+               fflush(stderr); \
+               exit(-1); \
+    }
+#endif
diff --git a/TBBT/trace_play/rfs_c_age.c b/TBBT/trace_play/rfs_c_age.c
new file mode 100644 (file)
index 0000000..cdf9c6c
--- /dev/null
@@ -0,0 +1,1393 @@
+/* rfs_age_unit_base.c */
+#include <sys/vfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include "rfs_assert.h"
+#include "profile.h"
+#define MKDIR 1
+#define RMDIR 2
+#define CREATE 3
+#define REMOVE 4
+#define WRITE 5
+#define TRUNCATE 6
+
+#define MAX_FILES 400000
+#define MAX_DIRS  100000
+#define FILE_FH_HTABLE_SIZE MAX_FILES
+#define MAX_NAMELEN 512
+#define MAX_PLAY_PATH_SIZE 256
+//#define MAX_COMMAND_LEN (MAX_PLAY_PATH_SIZE+16)
+//#define NFS_MAXDATA 4096
+#define NFS_MAXDATA 32768
+#define TRACE_FH_SIZE 64
+
+#define FH_T_FLAG_FREE 0
+#define FH_T_FLAG_IN_USE 1
+#define IS_FILE 0
+#define IS_DIR 1
+#define EXIST 0
+#define NON_EXIST 1
+#define COMPLETE 3
+#define ACTIVE 0
+#define INACTIVE 1
+#define DONT_CARE 2
+
+int EVEN_CHUNK_SIZE = 0;
+int STAGE_NUM = 10;
+
+static char ftypename[3][32] = {"FILE", "DIR", "FTYPE_DONT_CARE"};
+static char activename[3][32] = {"ACTIVE", "INACTIVE", "ACTIVE_DONT_CARE"};
+static char existname[4][32] = {"EXIST", "NON_EXIST", "EXIST_DONT_CARE", "COMPLETE"};
+
+typedef struct {
+    char flag;
+       char ftype;
+       char exist_flag;
+       int psfh;
+       int size;
+       int cur_size;
+       int accumulated_write_size;
+    //char trace_fh [TRACE_FH_SIZE+1];
+    char path[MAX_PLAY_PATH_SIZE];
+} fh_t;
+
+typedef struct {
+       char name[32];
+       fh_t * fh;
+       //struct generic_entry * htable;
+       int fh_size;
+       int fh_max;
+       int active_fh_max;
+       //int index;
+       //int htable_size;
+} fh_info_t;
+
+fh_info_t obj_fh;
+profile_t read_line_profile, fgets_profile;
+char trace_file[MAX_NAMELEN];
+FILE * profile_fp = NULL;
+char testdir[MAX_NAMELEN];
+
+int active_obj_num = 0;
+int exist_active_obj_num = 0;
+static int active_file_num = 0, active_dir_num =0, age_file_num = 0, age_dir_num = 0;
+
+int age_create_num = 0;
+int age_mkdir_num = 0;
+int assure_create_num = 0;
+int assure_mkdir_num = 0;
+int age_write_num = 0;
+int nonage_write_num = 0;
+int overlap_write_num = 0;
+
+int fs_size_MB = 0, fs_size = 0;
+int rfs_debug = 0;
+
+
+int ACTIVE_RATIO;
+int FILE_RATIO = 50;
+int WRITE_CHUNK_NUM;
+int MAX_FS_SIZE_MB = 1000000; 
+int DISK_FRAGMENT_SIZE = 4096;
+int DISK_FRAGMENT_SIZE_MASK = 0xFFFFF000;
+
+int MIN_WRITE_SIZE;
+
+int aging_dirs ()
+{
+
+}
+
+int f()
+{};
+
+int init_profile_variables()
+{
+       init_profile ("read_line profile", &read_line_profile);
+       init_profile ("fgets profile", &fgets_profile);
+}
+
+int init_fh_info (char * name, fh_info_t * fh_infop, int fh_size, int htable_size)
+{
+       int i;
+
+       RFS_ASSERT (strlen(name) < sizeof(fh_infop->name));
+       strcpy (fh_infop->name, name);
+       fh_infop->fh_max = 0;
+       //fh_infop->index = 0;
+       fh_infop->fh_size = fh_size;
+       //fh_infop->htable_size = htable_size;
+       fh_infop->fh = (fh_t *)malloc (sizeof(fh_t)*fh_size);
+       RFS_ASSERT (fh_infop->fh);
+       //fh_infop->htable = malloc (sizeof(struct*generic_entry)*htable_size);
+       //RFS_ASSERT (fh_infop->htable);
+       printf("initialize %s size %d bytes\n", 
+               //name, sizeof(fh_t)*fh_size + sizeof(struct*generic_entry)*htable_size);
+               name, sizeof(fh_t)*fh_size);
+
+       for (i=0; i<fh_size; i++)
+               fh_infop->fh[i].flag = FH_T_FLAG_FREE;
+}
+
+int init()
+{
+//     init_fh_info ("file_fh", &file_fh, MAX_FILES, MAX_FILES);
+//     init_fh_info ("dir_fh", &dir_fh, MAX_DIRS, MAX_DIRS);
+       init_fh_info ("obj_fh", &obj_fh, MAX_FILES+MAX_DIRS, MAX_FILES+MAX_DIRS);
+}
+
+int add_fh_t (fh_info_t * fh_table, char * path, int sfh, int psfh, int size, int ftype, int exist_flag, int active_flag)
+{
+       int i;
+
+       if (size == -1) 
+               fs_size += DISK_FRAGMENT_SIZE;
+       else {
+               fs_size += ((size+DISK_FRAGMENT_SIZE-1) & DISK_FRAGMENT_SIZE_MASK);
+               if (size > (DISK_FRAGMENT_SIZE*12))     // first indirect block
+                       fs_size += DISK_FRAGMENT_SIZE;
+       }
+       if (fs_size > 1000000) {
+               fs_size_MB += fs_size/1000000;
+               fs_size = fs_size % 1000000;
+       }
+
+       RFS_ASSERT (sfh >0);
+
+       if (active_flag == ACTIVE)
+               active_obj_num ++;
+       else
+               RFS_ASSERT (sfh >= fh_table->active_fh_max);
+
+       if (rfs_debug)
+               printf ("add to %s path %s sfh %d size %d %s %s %s\n", fh_table->name, path, sfh, size, 
+               ftypename[ftype], existname[exist_flag], activename[active_flag]);
+
+       RFS_ASSERT ( (sfh>=0) && (sfh<fh_table->fh_size) );
+       RFS_ASSERT (fh_table->fh[sfh].flag==FH_T_FLAG_FREE);
+       fh_table->fh[sfh].flag = FH_T_FLAG_IN_USE;
+       if (sfh >= fh_table->fh_max)
+               fh_table->fh_max = sfh+1;
+       RFS_ASSERT (strlen(path)<MAX_PLAY_PATH_SIZE);
+       strcpy (fh_table->fh[sfh].path, path);
+       fh_table->fh[sfh].psfh = psfh;
+       fh_table->fh[sfh].size = size;
+       fh_table->fh[sfh].cur_size = 0;
+       fh_table->fh[sfh].accumulated_write_size = 0;
+       fh_table->fh[sfh].ftype = ftype;
+       fh_table->fh[sfh].exist_flag = exist_flag;
+       if (active_flag == ACTIVE) {
+               if (ftype == IS_FILE)
+                       active_file_num ++;
+               else {
+                       RFS_ASSERT (ftype== IS_DIR);
+                       active_dir_num ++;
+               }
+       } else {
+               if (ftype == IS_FILE)
+                       age_file_num ++;
+               else {
+                       RFS_ASSERT (ftype== IS_DIR);
+                       age_dir_num ++;
+               }
+       }
+       //print_fh_map(fh_table);
+}
+
+
+int loop_write (int fd, char * buf, int buflen)
+{
+    int ret;
+    int pos = 0;
+
+    while (1) {
+        ret = write (fd, buf+pos, buflen-pos);
+
+        if (ret == -1) {
+                       RFS_ASSERT (errno == ENOSPC);
+                       fflush(stdout);
+            perror ("loop write");
+                       check_free_blocks(0);
+                       return -1;
+        }
+        if (ret == buflen-pos)
+            break;
+        pos += ret;
+    }
+    return 0;
+}
+
+int assure_exist(int sfh, char * path, int ftype_flag)
+{
+       char name[MAX_NAMELEN];
+       int ret;
+       char *p, *q;
+       int non_exist_flag = 0;
+       int count=0;
+       struct stat st;
+
+       if (rfs_debug)
+               printf("assure_exist %s\n", path);
+
+       ret = stat (path, &st);
+       if (ret == 0) {
+               if (ftype_flag == IS_DIR) {
+                       RFS_ASSERT (st.st_mode & S_IFDIR);
+                       RFS_ASSERT (!(st.st_mode & S_IFREG));
+               } else {
+                       RFS_ASSERT (st.st_mode & S_IFREG);
+                       RFS_ASSERT (!(st.st_mode & S_IFDIR));
+               }
+               return 0;
+       }
+       if (errno!=ENOENT) {
+               perror(path);
+       }
+       //RFS_ASSERT (errno == ENOENT);
+       
+       p = path;
+       q = name;
+       if (*p=='/') {
+               *q='/';
+               p++;
+               q++;
+       }
+       while (count++<100) {
+               /* copy the next component from path to name */
+               for (; *p!=0 && *p!='/'; p++, q++ ) 
+                       *q = *p;
+               *q = 0;
+               ret = stat (name, &st);
+               if (ret == -1) {
+                       if (errno != ENOENT)
+                               perror (name);
+                       RFS_ASSERT (errno == ENOENT)
+                       if ((*p)==0 && (ftype_flag==IS_FILE)) {
+                               ret = creat (name, S_IRWXU);
+                               if (ret == -1)
+                                       perror (name);
+                               RFS_ASSERT (ret >=0);
+                               assure_create_num ++;
+                               if (rfs_debug)
+                                       printf("sfh %d create %s\n", sfh, name);
+                               close(ret);
+                       } else {
+                               ret = mkdir (name, S_IRWXU);
+                               if (ret == -1)
+                                       perror (name);
+                               RFS_ASSERT (ret >=0);
+                               assure_mkdir_num ++;
+                               if (rfs_debug) {
+                                       if (*p==0) 
+                                               printf("sfh %d mkdir %s\n", sfh, name);
+                                       else
+                                               printf("sfh %d middle mkdir %s\n", sfh, name);
+                               }
+                               RFS_ASSERT (ret ==0);
+                       }
+               }
+               if ((*p)=='/') {
+                       *q = '/';
+                       p++; q++;
+               } else {
+                       RFS_ASSERT ((*p)==0)
+                       return 0;
+               }
+       }
+       RFS_ASSERT (0);
+}
+
+
+int print_fh_map(fh_info_t * fhp)
+{
+       int i;
+       int num = 0;
+       int active_obj_num = 0;
+
+
+       for (i=0; i<fhp->fh_max; i++) {
+               if (fhp->fh[i].flag == FH_T_FLAG_IN_USE) {
+                       num ++;
+                       if (i < fhp->active_fh_max)
+                               active_obj_num++;
+
+                       if (rfs_debug)
+                               printf("%s[%d] %s %s %s\n", fhp->name, i, fhp->fh[i].path, ftypename[fhp->fh[i].ftype], existname[fhp->fh[i].exist_flag]);
+               }
+       }
+       fprintf(stderr, "fh_max %d active_fh_max %d, in_use_num %d entries active_obj_num %d \n", fhp->fh_max, fhp->active_fh_max, num, active_obj_num);
+}
+
+void read_fh_map_line_skimmer (char * buf)
+{
+       char * p;
+       char name[MAX_NAMELEN];
+       int psfh, sfh, size;
+       char filename[MAX_NAMELEN];
+
+       sfh = 0;
+       if (!strncmp(buf, "::DIR ", strlen("::DIR "))) {
+               strcpy (name, testdir);
+               if (buf[6]=='/') {
+                       sscanf(buf, "::DIR %s %d\n", name+strlen(name), &sfh);
+                       add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, NON_EXIST, ACTIVE);
+               } /* else { 
+                       RFS_ASSERT (!strncmp(buf,"::DIR Fake 1\n", strlen("::DIR Fake 1\n")));
+                       sfh = 1;
+                       add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, EXIST, ACTIVE);
+                       exist_active_obj_num ++;
+               } */
+       } else {
+
+               if (!strncmp(buf, "::TBDIR", strlen("::TBDIR"))) 
+                       return; 
+
+               p = strstr(buf, "parent");
+               RFS_ASSERT (p);
+               sscanf(p, "parent %d\n", &psfh);
+               RFS_ASSERT (obj_fh.fh[psfh].flag == FH_T_FLAG_IN_USE);
+               p = strstr(p, "name");
+               RFS_ASSERT (p);
+               if (!strncmp(p, "name xx", strlen("name xx"))) {
+                       sscanf(p, "name xx-%s sfh %d size %x", filename, &sfh, &size);
+                       //printf ("name xx-%s sfh %d\n", filename, sfh);
+               } else {
+                       sscanf(p, "name \"%s sfh %d size %x", filename, &sfh, &size);
+                       //printf ("name %s sfh %d\n", filename, sfh);
+                       filename[strlen(filename)-1]=0;
+               }
+               strcpy (name, obj_fh.fh[psfh].path);    
+               strcat (name, "/");
+               strcat (name, filename);
+               add_fh_t (&obj_fh, name, sfh, psfh, size, IS_FILE, NON_EXIST, ACTIVE);
+       }
+}
+
+void read_fh_map_line_ls (char * buf)
+{
+       static int sfh = 2;
+       int size;
+       char name[MAX_NAMELEN];
+       char * p = name;
+       
+       strcpy (name, testdir);
+       strcat (name, "/");
+       if (strchr(buf, ' ')) {
+               sscanf(buf, "%d %s\n", &size, p+strlen(name));
+               add_fh_t (&obj_fh, name, sfh, -1, size, IS_FILE, NON_EXIST, ACTIVE);
+       } else {
+               sscanf(buf, "%s\n", p+strlen(name));
+               add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, NON_EXIST, ACTIVE);
+       };
+       sfh ++;
+}
+
+void read_fh_map (char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       int lineno = 0;
+       int fh_map_debug =0;
+#define FH_MAP_FORMAT_SKIMMER  0
+#define FH_MAP_FORMAT_LS               1
+       int fh_map_format;
+
+       if (strstr(fh_map_file, ".ski"))
+               fh_map_format = FH_MAP_FORMAT_SKIMMER;
+       else
+               fh_map_format = FH_MAP_FORMAT_LS;
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       
+
+       memset(buf, 0, sizeof(buf));
+
+       while (fgets(buf, 1024, fp)) {
+               RFS_ASSERT (fh_map_debug==0);
+               lineno ++;
+               if (rfs_debug)
+                       printf ("line %d %s", lineno, buf);
+               if (lineno % 10000==0)
+                       printf("%d fh_map entry read\n", lineno);
+               if (fh_map_format == FH_MAP_FORMAT_SKIMMER)
+                       read_fh_map_line_skimmer(buf);
+               else 
+                       read_fh_map_line_ls (buf);
+       }
+                       
+       fclose(fp);
+       obj_fh.active_fh_max  = obj_fh.fh_max;
+       if (fh_map_debug) {
+               print_fh_map (&obj_fh);
+       }
+}
+
+int print_usage()
+{
+       printf("\n\nagefs fmt4 HOLDER_NUM HOLDER_SIZE DISK_FRAGMENT_SIZE testdir\n");
+       printf("Note: fmt4 is used to initialize the holders in a logical partition before starting writing aged files in a specific pattern as by fmt3 command\n");
+
+       printf("\n\nagefs fmt3 aged_file CHUNK_SIZE CHUNK_DISTANCE CHUNK_NUM START_BNO HOLDER_SIZE HOLDER_NUM DISK_FRAGMENT_SIZE testdir\n");
+       printf("Note: one file is written as CHUNK_NUM number of continuous chunks on disk, each chunk is of CHUNK_SIZE blocks, the distance between two adjacent chunks is CHUNK_DISTANCE blocks\n");
+
+       printf("\n\nagefs fmt2 size1 .. size_n num testdir\n");
+       printf("Note: N file is writen interleavingly for _num_ times, each time _size1_ bytes is written to file1, _size2_ bytes is written to file2, _sizen_ bytes is written to filen\n");
+
+       printf("\n\nagefs EVEN_CHUNK_SIZE FILE_RATIO ACTIVE_RATIO WRITE_CHUNK_NUM MAX_FS_SIZE_MB STAGE_NUM fh_path_map testdir\n");
+       printf("Note: EVEN_CHUNK_SIZE: if 1, each file is chopped to equal size chunks, if 0, each file size is chopped randomly but with the average size to be CHUNK_SIZE");
+       printf("          FILE_RATIO: percentage of number of inactive files over number of inactive file system objects\n");
+       printf("      ACTIVE_RATIO: percentage of number of active file system objects over all file system objects\n");
+       printf("      WRITE_CHUNK_NUM: when a file is initialized, it is written in several open-close session interleved with writes to other files. Except small files where file_size/WRITE_CHUNK_SIZE is less than DISK_FRAGMENT_SIZE, each open-close session on the average write (file_size/WRITE_CHUNK_NUM) bytes. \n");
+       printf("          MAX_FS_SIZE_MB: another condition to stop initialization, either all active file is initialized, or max file system size is reached\n");
+       printf("          STAGE_NUM: divide the writing of files into several stages, each stage finish initialization of some of the files. The bigger the STAGE_NUM, the less concurrency is there\n");
+}
+
+inline char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+
+#define READ_LINE_BUF_SIZE 1000
+#define READ_LINE_LENGTH 32
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                               RFS_ASSERT (0);
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       fclose(fp);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+int print_result()
+{
+       struct statfs stfs;
+       int ret;
+       static struct statfs first_stfs;
+       static int first_entry = 1;
+
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       if (first_entry) {
+               first_entry = 0;
+               first_stfs = stfs;
+       }
+
+       fprintf(stderr, "active_file_num %d active_dir_num %d age_file_num %d age_dir_num %d\n",
+               active_file_num, active_dir_num, age_file_num, age_dir_num);
+       fprintf(stderr, "number of used file nodes %d, used (4K) blocks in fs %d (%d MB)\n", first_stfs.f_ffree-stfs.f_ffree, first_stfs.f_bfree - stfs.f_bfree, (first_stfs.f_bfree-stfs.f_bfree)/(1000000/DISK_FRAGMENT_SIZE));
+       fprintf(stderr, "assure_create_num %d assure_mkdir_num %d\n", assure_create_num, assure_mkdir_num);
+}
+
+typedef struct {
+    int     pcnt;       /* percentile */
+    int     size;       /* file size in KB */
+} sfs_io_file_size_dist;
+
+sfs_io_file_size_dist Default_file_size_dist[] = {
+    /* percentage   KB size */
+#ifdef notdef
+       {   100,    128},                       
+    {    94,     64},           /*  4% */
+    {    97,    128},           /*  3% */
+#endif
+    {    33,      1},           /* 33% */
+    {    54,      2},           /* 21% */
+    {    67,      4},           /* 13% */
+    {    77,      8},           /* 10% */
+    {    85,     16},           /*  8% */
+    {    90,     32},           /*  5% */
+    {    94,     64},           /*  4% */
+    {    97,    128},           /*  3% */
+    {    99,    256},           /*  2% */
+    {   100,   1024},           /*  1% */
+    {     0,      0}
+};
+
+/*
+ * For a value between 0-99, return a size based on distribution
+ */
+static int
+get_file_size()
+{
+       static file_array_initialized = 0;
+       static int file_size_array[100];
+       int i;
+
+       i = random() % 100;
+
+    if (i < 0 || i > 99)
+    return (0);
+
+    if (file_array_initialized == 0) {
+           int j, k;
+       for (j = 0, k = 0; j < 100; j++) {
+               if (j >= Default_file_size_dist[k].pcnt &&
+               Default_file_size_dist[k + 1].size != 0)
+           k++;
+               file_size_array[j] = Default_file_size_dist[k].size * 1024;
+       }
+       file_array_initialized++;
+    }
+    return (file_size_array[i]);
+}
+
+int range_random(int min, int max)
+{
+       int i;
+       i = (random()%(max-min)) + min;
+       return i;
+}
+
+/* answer 1 with a probability of percent/100 */
+int decide(int percent)
+{
+       int i = random()%100;
+       if (i<percent)
+               return 1;
+       else
+               return 0;
+}
+
+int select_obj (fh_info_t * fhp, int ftype, int exist_flag, int active_flag, int min, int max)
+{
+       int i;
+       int sfh, count = 0;
+
+       //printf ("select_obj %s %s %s\n", ftypename[ftype], existname[exist_flag], activename[active_flag]);
+       if (active_flag == ACTIVE) {
+               sfh = range_random (0, fhp->active_fh_max);
+               for (i=0; i<fhp->active_fh_max; i++) {
+                       if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
+                               ((ftype==DONT_CARE) || (ftype ==fhp->fh[sfh].ftype)) &&
+                               ((exist_flag==DONT_CARE) || (fhp->fh[sfh].exist_flag == exist_flag))) {
+                               return sfh;
+                               }
+                       sfh = (sfh+1) % fhp->active_fh_max;
+               }
+       } else {
+               //min = 0;
+               //max = fhp->fh_max;
+               //printf ("select_obj min %d max %d\n", min, max);
+               RFS_ASSERT (active_flag == DONT_CARE);
+               RFS_ASSERT (exist_flag == EXIST);
+               sfh = range_random (min, max);
+               for (i=min; i<max; i++) {
+               //      printf("check %d\n", sfh);
+                       RFS_ASSERT ((sfh>=min) && (sfh<max));
+                       if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
+                           ((ftype==DONT_CARE) || (fhp->fh[sfh].ftype == ftype)) &&
+                               (fhp->fh[sfh].exist_flag == EXIST)) {
+                               return sfh;
+                       }
+                       sfh++;
+                       if (sfh==max)
+                               sfh = min;
+               }
+       }
+/*
+       for (i=min; i<max; i++) {
+               if ((fhp->fh[i].flag == FH_T_FLAG_IN_USE) &&
+                       (fhp->fh[i].ftype == IS_FILE)                           ) {
+                       if (fhp->fh[i].exist_flag == EXIST) {
+                               printf ("actually %d\n", i);
+                       }
+                       RFS_ASSERT (fhp->fh[i].exist_flag != EXIST);
+                       RFS_ASSERT (fhp->fh[i].exist_flag == COMPLETE);
+               }
+       }
+*/
+       return -1;
+}
+
+/* append "size" to file "path" */
+int append_file (int sfh, char * path, int size)
+{
+       int fd;
+       int written_bytes = 0;
+       int ret;
+#define BUF_SIZE 32768
+       static char buf[BUF_SIZE];
+
+       if (rfs_debug)
+               printf ("sfh %d append_file %s size %d\n", sfh, path, size);
+
+       fd = open (path, O_WRONLY|O_APPEND);
+       if (fd==-1)
+               perror(path);
+       RFS_ASSERT (fd > 0);
+       
+       while (written_bytes+NFS_MAXDATA < size) {
+               ret = loop_write (fd, buf, NFS_MAXDATA);
+               RFS_ASSERT (ret!=-1);
+               written_bytes += NFS_MAXDATA;
+       }
+       ret = loop_write (fd, buf, size-written_bytes);
+       RFS_ASSERT (ret!=-1);
+       close(fd);
+}
+
+int get_write_size (int target_size, int cur_size)
+{
+       int i;
+
+       if (target_size - cur_size < MIN_WRITE_SIZE)
+               return (target_size - cur_size);
+
+       /* target_size/WRITE_CHUNK_NUM would be the average value of i */
+       if (target_size < WRITE_CHUNK_NUM) {
+               i = MIN_WRITE_SIZE;
+       } else {
+
+               if (EVEN_CHUNK_SIZE)
+                       i = target_size/WRITE_CHUNK_NUM;
+               else
+                       i = random() % (2*(target_size/WRITE_CHUNK_NUM));
+
+               if (i < MIN_WRITE_SIZE)
+                       i = MIN_WRITE_SIZE;
+       }
+
+       if (i > (target_size - cur_size))
+               i = target_size - cur_size;
+
+       return i;
+}
+
+FILE * fplog;
+
+
+int CHUNK_SIZE;
+int CHUNK_DISTANCE;
+int CHUNK_NUM;
+int START_BNO;
+int HOLDER_NUM;
+int HOLDER_SIZE;
+int INDIRECT_FANOUT;
+char agename[1024];
+
+#define MAX_DISK_FRAGMENT_SIZE 4096
+#define MAX_HOLDER_SIZE 10
+#define HOLDER_DIR_NUM 1
+#define DUMMY_FILE_COUNT 1000
+
+main4(int argc, char ** argv)
+{
+       int i, j;
+       char name[256];
+       char cmd[1024];
+       char * buf;
+       int fd, ret;
+       char testdir[1024];
+
+       if (argc!=6) {
+               print_usage();
+               return;
+       }
+       i = 2;
+       HOLDER_NUM = atoi(argv[i++]);
+       HOLDER_SIZE = atoi(argv[i++]);
+       DISK_FRAGMENT_SIZE = atoi(argv[i++]);
+       RFS_ASSERT (DISK_FRAGMENT_SIZE <= MAX_DISK_FRAGMENT_SIZE);
+       DISK_FRAGMENT_SIZE_MASK = ~(DISK_FRAGMENT_SIZE-1);
+       RFS_ASSERT ((DISK_FRAGMENT_SIZE_MASK == 0xFFFFF000) ||
+                               (DISK_FRAGMENT_SIZE_MASK == 0xFFFFFC00)         );
+       strcpy (testdir, argv[i]);
+
+       fprintf(fplog, "main4: initialize the holders HOLDER_NUM %d HOLDER_SIZE %d DISK_FRAGMENT_SIZE %d testdir %s\n",
+                       HOLDER_NUM, HOLDER_SIZE, DISK_FRAGMENT_SIZE, testdir);
+       fflush(fplog);
+
+       buf = (char *)malloc (HOLDER_SIZE*DISK_FRAGMENT_SIZE);
+       RFS_ASSERT (buf);
+
+       /* create some dummy files */
+       for (i=0; i<DUMMY_FILE_COUNT; i++) {
+               memset (name, 0, sizeof(name));
+               sprintf(name, "%s/dummy%d", testdir, i);
+               fd = creat (name, S_IRWXU);
+               if (fd == -1) {
+                       perror(name);
+                       exit(-1);
+               }
+               close (fd);
+       }
+
+       /* create directories */
+       if (HOLDER_DIR_NUM !=1) {
+               for (i=0; i<HOLDER_DIR_NUM; i++) {
+                       memset (name, 0, sizeof(name));
+                       sprintf(name, "%s/%d", testdir, i);
+                       ret = mkdir (name, S_IRWXU);
+                       if (ret == -1) {
+                               perror(name);
+                               exit(-1);
+                       }
+               }
+       }
+
+       /* create regular files */
+       for (j=0; j<HOLDER_DIR_NUM; j++) {
+               for (i=0; i<HOLDER_NUM/HOLDER_DIR_NUM; i++) {
+                       if (HOLDER_DIR_NUM == 1)  
+                               sprintf(name, "%s/%d", testdir, i);
+                       else
+                               sprintf(name, "%s/%d/%d", testdir, j, i);
+                       fd = open (name, O_CREAT|O_WRONLY);
+                       if (fd == -1) {
+                               perror(name);
+                               exit(-1);
+                       }
+                       ret = loop_write (fd, buf, HOLDER_SIZE*DISK_FRAGMENT_SIZE);
+                       close (fd);
+                       if (ret == -1) 
+                               break;
+               }
+       }
+
+#ifdef notdef
+       /* delete the dummy files */
+       for (i=0; i<DUMMY_FILE_COUNT; i++) {
+               memset (name, 0, sizeof(name));
+               sprintf(name, "%s/dummy%d", testdir, i);
+               ret = unlink (name);
+               if (ret == -1) {
+                       perror(name);
+                       exit(-1);
+               }
+       }
+#endif
+}
+
+int append_space_occupier()
+{
+       static char name [1024];
+       static FILE * fp = NULL;
+       char buf[MAX_DISK_FRAGMENT_SIZE];
+       int ret;
+       if (fp == NULL) {
+               sprintf(name, "%s/space_ocuupier", testdir);
+               fp = fopen (name, "a+");
+               RFS_ASSERT (fp!= NULL);
+               ret = fwrite (buf, DISK_FRAGMENT_SIZE, 1, fp);
+               if (ret != 1) {
+                       perror("append space occupier");
+               }
+               fclose (fp);
+               fp = NULL;
+       };
+       ret = fwrite (buf, DISK_FRAGMENT_SIZE, 1, fp);
+       if (ret != 1) {
+               perror("append space occupier");
+       }
+       RFS_ASSERT (ret == 1);
+}
+
+int create_one_dummy_file()
+{
+       int i, fd, ret;
+       static int index = 0;
+       static char name[1024];
+       struct stat st;
+
+       for (i=0; i<DUMMY_FILE_COUNT; i++) {
+               index = (index+1) % DUMMY_FILE_COUNT;
+               sprintf(name, "%s/dummy%d", testdir, i);
+               ret = stat (name, &st);
+               if (ret == -1) {
+                       RFS_ASSERT (errno == ENOENT);
+                       fd = open (name, O_CREAT|O_WRONLY);
+                       RFS_ASSERT (fd >=0);
+                       close (fd);
+                       return 0;
+               };
+       }
+}
+
+int delete_one_dummy_file()
+{
+       int i,ret;
+       static int index = 0;
+       static char name[1024];
+       struct stat st;
+
+       for (i=0; i<DUMMY_FILE_COUNT; i++) {
+               index = (index+1) % DUMMY_FILE_COUNT;
+               sprintf(name, "%s/dummy%d", testdir, i);
+               ret = stat (name, &st);
+               if (ret == 0) {
+                       ret = unlink (name);
+                       RFS_ASSERT (ret == 0);
+                       return;
+               } else
+                       RFS_ASSERT (errno == ENOENT);
+       }
+       RFS_ASSERT (0);
+}
+
+int create_sub_holder_file(int holderno, int sub_holderno)
+{
+       char name[256];
+       int fd, ret;
+       static char buf[MAX_DISK_FRAGMENT_SIZE];
+
+
+       RFS_ASSERT (MAX_DISK_FRAGMENT_SIZE >= DISK_FRAGMENT_SIZE);
+
+       sprintf(name, "%d.%d", holderno, sub_holderno);
+       printf ("create/write %s\n", name);
+       fd = open (name, O_CREAT|O_WRONLY);
+       RFS_ASSERT (fd >=0);
+       loop_write (fd, buf, DISK_FRAGMENT_SIZE);
+       close(fd);
+}
+
+int get_free_blocks ()
+{
+       static struct statfs stfs;
+       int ret;
+
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       return (stfs.f_bfree);
+}
+
+int print_free_blocks (char *string)
+{
+       static struct statfs stfs;
+       int ret;
+
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       printf("%s f_bfree %d \n", string, stfs.f_bfree);
+}
+
+int check_free_blocks (int num)
+{
+       static struct statfs stfs;
+       int ret;
+
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       if (stfs.f_bfree!=num) {
+               printf("f_bfree %d expected %d\n", stfs.f_bfree, num);
+               RFS_ASSERT (0);
+       }
+}
+
+int progress_on_aged_file(int * num)
+{
+       char buf[MAX_DISK_FRAGMENT_SIZE*MAX_HOLDER_SIZE];
+       static need_indirect_blocks = 0;
+       static skip_for_indirect_blocks = 0;
+       static int blkno = 0;
+
+       printf ("\n");
+       print_free_blocks("progress_on_aged_file begin");
+
+       if (skip_for_indirect_blocks == need_indirect_blocks) {
+               //check_free_blocks(free_block_num);
+               //RFS_ASSERT (free_block_num >= (1+need_indirect_blocks));
+               (*num) --;
+               printf("append to aged file %d bytes\n", DISK_FRAGMENT_SIZE);
+               append_file (0, agename, DISK_FRAGMENT_SIZE);
+               //*free_block_num -= (need_indirect_blocks +1)
+               //check_free_blocks(free_block_num);
+
+               blkno ++;
+               if (((blkno - 12) % INDIRECT_FANOUT) == 0) {
+                       if (((blkno - (INDIRECT_FANOUT+12)) % (INDIRECT_FANOUT*INDIRECT_FANOUT)) == 0) {
+                               if (blkno == 12 + INDIRECT_FANOUT + INDIRECT_FANOUT*INDIRECT_FANOUT) {
+                                       printf ("need_indirect_blocks is set to 3 blkno %d\n", blkno);
+                                       need_indirect_blocks = 3;
+                               } else {
+                                       printf ("need_indirect_blocks is set to 2 blkno %d\n", blkno);
+                                       need_indirect_blocks = 2;
+                               }
+                       } else {
+                               printf ("need_indirect_blocks is set to 1 blkno %d\n", blkno);
+                               need_indirect_blocks = 1;
+                       };
+               } else {
+                       need_indirect_blocks = 0;
+               }
+               skip_for_indirect_blocks = 0;  
+       } else {
+               skip_for_indirect_blocks ++;  
+       }
+
+       printf ("skip_for_indirect_blocks -- %d\n", skip_for_indirect_blocks);
+       print_free_blocks("progress_on_aged_file end");
+}
+
+int free_blocks (char * agename, int start, int num)
+{
+       int holderno;
+       char name [128];
+       int ret;
+       struct stat st;
+       int sub_holderno;
+       int i;
+
+       printf ("free_blocks start %d  num %d\n", start, num);
+
+BEGIN:
+       check_free_blocks(0);
+       if (num == 0)
+               return start;
+       holderno = start/HOLDER_SIZE;
+       sub_holderno = start%HOLDER_SIZE;
+
+       sprintf (name, "%d", holderno);
+       
+       ret = stat (name, &st);
+       if (ret == -1) {
+               RFS_ASSERT (errno == ENOENT);
+               for (i=sub_holderno; (i<HOLDER_SIZE && num>0); i++) {
+                       sprintf(name, "%d.%d", holderno, i);
+                       ret = stat (name, &st);
+                       if (ret == 0) {
+
+                               printf ("sub_holder file %s is unlinked\n", name);
+                               ret = unlink(name);
+                               RFS_ASSERT (ret == 0);
+
+                               create_one_dummy_file();
+
+                               printf ("write to age file %d bytes\n", DISK_FRAGMENT_SIZE);
+
+                               progress_on_aged_file(&num);
+
+                       } else { 
+                               printf ("sub_holder file %s is already used\n", name);
+                               RFS_ASSERT ((ret == -1) && (errno ==ENOENT));
+                       }
+                       start ++;
+               }
+               goto BEGIN; 
+       }
+       
+       RFS_ASSERT (ret == 0);
+       RFS_ASSERT (st.st_size == HOLDER_SIZE * DISK_FRAGMENT_SIZE);
+       printf ("holder file %s is unlinked\n", name);
+       ret = unlink(name);
+       RFS_ASSERT (ret == 0);
+       check_free_blocks(HOLDER_SIZE);
+
+       /* create the sub holders before the first slot that we need */
+       for (i=0; i<sub_holderno; i++) {
+               delete_one_dummy_file();
+               create_sub_holder_file (holderno, i);
+       }
+
+       /*
+       i = (HOLDER_SIZE - sub_holderno) < num? (HOLDER_SIZE - sub_holderno): num;
+       sub_holderno += i;
+       start += i;
+       num -= i;
+       check_free_blocks (i);
+       ret = loop_write (agefd, buf, DISK_FRAGMENT_SIZE*i);
+       RFS_ASSERT (ret != -1);
+       */
+       i = HOLDER_SIZE - sub_holderno;
+       check_free_blocks(i);
+
+       while ((sub_holderno < HOLDER_SIZE) && (num>0)) {
+               sub_holderno ++;
+               start ++;
+
+               progress_on_aged_file(&num);
+                                               
+               RFS_ASSERT (ret != -1);
+       }
+
+       /* create the sub holders after the slot that we need */
+       for (i=sub_holderno; i<HOLDER_SIZE; i++) {
+               delete_one_dummy_file();
+               create_sub_holder_file (holderno, i);
+       }
+
+       create_one_dummy_file();
+       goto BEGIN;
+}
+
+int main3(int argc, char ** argv)
+{
+
+       int block_anchor;
+       int i;
+       int agefd;
+       char * buf;
+       char cwd[1024];
+       char * ret;
+       struct stat st;
+
+       if (argc!=11) {
+               print_usage();
+               return;
+       }
+       i = 2;
+
+       CHUNK_SIZE = atoi(argv[i++]);
+       CHUNK_DISTANCE = atoi (argv[i++]);
+       CHUNK_NUM = atoi (argv[i++]);
+       START_BNO = atoi (argv[i++]);
+       HOLDER_SIZE = atoi (argv[i++]);
+       RFS_ASSERT (HOLDER_SIZE <= MAX_HOLDER_SIZE);
+       HOLDER_NUM = atoi (argv[i++]);
+       DISK_FRAGMENT_SIZE = atoi (argv[i++]);
+       RFS_ASSERT (DISK_FRAGMENT_SIZE <= MAX_DISK_FRAGMENT_SIZE);
+       INDIRECT_FANOUT = (DISK_FRAGMENT_SIZE/sizeof(int));
+       strcpy (testdir, argv[i++]);
+       strcpy (agename, testdir);
+       strcat (agename, argv[i++]);
+       ret = stat (agename, &st);
+       if (ret!=-1) {
+               printf ("%s already exists\n", agename);
+       }       
+       RFS_ASSERT (errno == ENOENT);
+
+       fprintf(fplog, "main3: to age one file %s in a customized way, CHUNK_SIZE %d CHUNK_DISTANCE %d CHUNK_NUM %d START_BNO %d HOLDER_SIZE %d HOLDER_NUM %d DISK_FRAGMENT_SIZE %d MAX_DISK_FRAGMENT_SIZE %d testdir %s\n", agename, CHUNK_SIZE, CHUNK_DISTANCE, CHUNK_NUM, START_BNO, HOLDER_SIZE, HOLDER_NUM, DISK_FRAGMENT_SIZE, MAX_DISK_FRAGMENT_SIZE, testdir);
+       fflush(fplog);
+
+       /* change working directory */
+       ret = getcwd(cwd, sizeof(cwd));
+       RFS_ASSERT (ret == cwd);
+       i = chdir (testdir);
+       RFS_ASSERT (i==0);
+
+       if (START_BNO == -1) {
+               block_anchor = random() % (HOLDER_NUM*HOLDER_SIZE);
+       } else {
+               RFS_ASSERT (START_BNO >=0);
+               block_anchor = START_BNO % (HOLDER_NUM*HOLDER_SIZE);
+       }
+       while (get_free_blocks()!=0) {
+               print_free_blocks("fill up initial file system blocks using space occupier");
+               append_file (0, "/b6/space_occupier", DISK_FRAGMENT_SIZE);
+       };
+       delete_one_dummy_file();
+       agefd = open (agename, O_CREAT|O_WRONLY);
+       RFS_ASSERT (agefd>=0);
+       close (agefd);
+
+       buf = (char *)malloc (CHUNK_SIZE*DISK_FRAGMENT_SIZE);
+       RFS_ASSERT (buf);
+
+       for (i=0; i<CHUNK_NUM; i++) {
+               block_anchor = (block_anchor + CHUNK_DISTANCE) % (HOLDER_NUM * HOLDER_SIZE);    
+               block_anchor = free_blocks (agename, block_anchor, CHUNK_SIZE);
+       }
+
+       check_free_blocks(0);
+       i = chdir (cwd);
+       RFS_ASSERT (i==0);
+}
+
+int main2(int argc, char ** argv)
+{
+       int i, j;
+       int size[3], num;
+       FILE * fp[3];
+       char name[3][128];
+       char cmd[1024];
+
+       if (argc <= 4) {
+               print_usage();
+               return;
+       }
+       num = atoi(argv[argc-2]);
+       strcpy (testdir, argv[argc-1]);
+       fprintf(fplog, "main2: generate interleaved files\n");
+    fprintf(fplog, "testdir %s number of files %d ", testdir, num);
+       for (i=0; i<argc-4; i++) {
+               size[i] = atoi(argv[i+2]);
+               fprintf(fplog, "size[%d] %d ", i, size[i]);
+
+               RFS_ASSERT (size[i] >=0 && size[i] < 1000000000);
+               strcpy (name[i], testdir);
+               sprintf (name[i], "%s/file%d", testdir, i);
+               sprintf(cmd, "touch %s", name[i]);
+               system(cmd);
+               printf ("write %s \n", name[i]);
+       };
+       fprintf(fplog, "\n");
+       fflush(fplog);
+
+       for (j=0; j<num; j++) {
+               for (i=0; i<argc-4; i++)
+                       append_file (i, name[i], size[i]);
+       }
+}
+
+int main(int argc, char ** argv)
+{
+       int i;
+       char cmd[1024];
+       char AGELOG_NAME[1024]= "/home/ningning/agefs.log";
+
+       sprintf(cmd, "date >> %s", AGELOG_NAME);
+       system (cmd);
+       fplog = fopen(AGELOG_NAME, "a");
+       RFS_ASSERT (fplog);
+       for (i=0; i<argc; i++) {
+               fprintf(fplog, "%s ", argv[i]);
+       }
+       fprintf (fplog, "\n");
+
+       if (argc>1 && (!strcmp(argv[1], "fmt2"))) 
+               main2 (argc, argv);
+       else if (argc>1 && (!strcmp(argv[1], "fmt3"))) 
+               main3 (argc, argv);
+       else if (argc>1 && (!strcmp(argv[1], "fmt4"))) 
+               main4 (argc, argv);
+       else 
+               main1 (argc, argv);
+END:
+       fclose (fplog);
+       sprintf(cmd, "date >> %s", AGELOG_NAME);
+       system (cmd);
+}
+
+int main1(int argc, char ** argv)
+{
+       char * buf;
+       static int disk_index=0;
+       int nfs3proc, size, off, count;
+       char procname[16];
+       struct stat st;
+       int ret;
+       int i,j,k;
+       int ftype_flag = 0, active_flag = 0;
+       char name[MAX_PLAY_PATH_SIZE];  
+       int sfh, psfh;
+       char mapname[1024];
+
+       profile_t create_profile, write_profile;
+       if (argc!=9) {
+               print_usage();
+               return;
+       }
+
+       init();
+       EVEN_CHUNK_SIZE = atoi(argv[1]);
+       RFS_ASSERT ((EVEN_CHUNK_SIZE==0) || (EVEN_CHUNK_SIZE==1));
+       FILE_RATIO = atoi (argv[2]);
+       ACTIVE_RATIO = atoi(argv[3]);
+       WRITE_CHUNK_NUM = atoi(argv[4]);
+       MAX_FS_SIZE_MB = atoi(argv[5]);
+
+       if (WRITE_CHUNK_NUM==0)
+               MIN_WRITE_SIZE = 2000000000;
+       else {
+               //MIN_WRITE_SIZE = DISK_FRAGMENT_SIZE;
+               MIN_WRITE_SIZE = 1;
+       }
+
+       STAGE_NUM = atoi (argv[6]);
+       strcpy (mapname, argv[7]);
+       strcpy (testdir, argv[8]);
+       ret = stat (testdir, &st);
+       if ((ret == -1) && (errno==ENOENT)) {
+               ret = mkdir (testdir, S_IRWXU);
+       }
+       RFS_ASSERT (ret >= 0);
+
+       
+       /* add testdir to obj_fh */
+       add_fh_t (&obj_fh, testdir, 1, -1, -1, IS_DIR, EXIST, ACTIVE);
+       exist_active_obj_num ++;
+       if (ACTIVE_RATIO >0) 
+               read_fh_map (mapname);
+
+       print_fh_map(&obj_fh);
+       init_profile_variables();
+
+       fprintf(fplog, "main1: populate the file system with both trace files and randomly generated files\n");
+       fprintf(fplog, "EVEN_CHUNK_SIZE %d FILE_RATIO %d ACTIVE_RATIO %d WRITE_CHUNK_NUM %d MAX_FS_SIZE_MB %d STAGE_NUM %d fh_map %s testdir %s\n", EVEN_CHUNK_SIZE, FILE_RATIO, ACTIVE_RATIO, WRITE_CHUNK_NUM, MAX_FS_SIZE_MB, STAGE_NUM, mapname, testdir);
+       system("date");
+       printf("EVEN_CHUNK_SIZE %d FILE_RATIO %d ACTIVE_RATIO %d WRITE_CHUNK_NUM %d MAX_FS_SIZE_MB %d STAGE_NUM %d fh_map %s testdir %s\n", EVEN_CHUNK_SIZE, FILE_RATIO, ACTIVE_RATIO, WRITE_CHUNK_NUM, MAX_FS_SIZE_MB, STAGE_NUM, mapname, testdir);
+       fflush(fplog);
+
+       profile_fp = fplog;
+       init_profile ("create_profile", &create_profile);
+       init_profile ("write_profile", &write_profile);
+
+       start_profile (&create_profile);
+       printf ("start creat/mkdir, active_obj_num %d\n", active_obj_num);
+       for (i=0; (exist_active_obj_num <= active_obj_num) && (fs_size_MB < MAX_FS_SIZE_MB); i++) {
+
+               if ((i!=0) && ((i%10000)==0)) {
+                       fprintf (stderr, "\n%d object created, exist_active_obj_num %d expected size %d MB\n", i, exist_active_obj_num, fs_size_MB);
+               }
+
+               /* decide on the exact active obj or populated obj */
+               if (decide(ACTIVE_RATIO)) {
+                       sfh = select_obj (&obj_fh, DONT_CARE, NON_EXIST, ACTIVE, 0, obj_fh.fh_max);
+                       if (sfh == -1)
+                               break;
+
+                       obj_fh.fh[sfh].exist_flag = EXIST;
+                       exist_active_obj_num ++;
+                       ftype_flag = obj_fh.fh[sfh].ftype;
+                       size = obj_fh.fh[sfh].size;
+               } else {
+                       psfh = select_obj (&obj_fh, IS_DIR, EXIST, DONT_CARE, 0, obj_fh.fh_max);
+                       strcpy (name, obj_fh.fh[psfh].path);
+                       sfh = obj_fh.fh_max;
+                       sprintf(name+strlen(name), "/AGE%d", obj_fh.fh_max); 
+
+                       /* decide next obj is file or directory */
+                       if (decide(FILE_RATIO)) {
+                               ftype_flag = IS_FILE;
+                               size = get_file_size();
+                       } else {
+                               ftype_flag = IS_DIR;
+                               size = -1;
+                       }
+                       add_fh_t (&obj_fh, name, sfh, psfh, size, ftype_flag, EXIST, INACTIVE);
+
+               }
+
+               /* make sure/create the  obj pathname on disk */
+               assure_exist (sfh, obj_fh.fh[sfh].path, ftype_flag);
+               /* write file to sizes according certain distribution 
+               if (ftype_flag == IS_FILE) 
+                       append_file (obj_fh.fh[sfh].path, obj_fh.fh[sfh].size);
+               */
+       }
+       fprintf (stderr, "\n%d object created, exist_active_obj_num %d expected size %d MB\n", i, exist_active_obj_num, fs_size_MB);
+
+       end_profile (&create_profile);
+       start_profile (&write_profile);
+       //write_file_range (0, obj_fh.fh_max);
+       for (i=1; i<=STAGE_NUM; i++) {
+               write_file_range (obj_fh.fh_max*(i-1)/STAGE_NUM, obj_fh.fh_max*i/STAGE_NUM);
+               //fprintf(stderr, "getchar\n");
+               //getchar();
+       }
+       end_profile (&write_profile);
+
+       print_profile ("create_profile", &create_profile);
+       print_profile ("write_profile", &write_profile);
+       printf ("exist_active_obj_num %d active_obj_num %d fs_size_MB %d\n",
+                       exist_active_obj_num, active_obj_num, fs_size_MB);
+
+       print_fh_map(&obj_fh);
+       print_result();
+       printf ("end of file system initialization\n");
+       system("date");
+}
+
+int write_file_range (int min, int max)
+{
+       int i, j, k, sfh;
+       int write_size, disk_write_size;
+
+       i = 0, j=0, k=0;
+       printf ("start writing files min %d max %d\n", min, max);
+       while (1) {
+               sfh = select_obj (&obj_fh, IS_FILE, EXIST, DONT_CARE, min, max);
+/*
+               if (!decide(obj_fh.fh[sfh].size*100/(MIN_WRITE_SIZE*WRITE_CHUNK_NUM))) {
+                       printf("skip writing small file\n");
+                       continue;
+               }
+*/
+               if (sfh == -1)
+                       break;
+               write_size = get_write_size (obj_fh.fh[sfh].size, obj_fh.fh[sfh].cur_size);
+               obj_fh.fh[sfh].cur_size += write_size;
+               if (obj_fh.fh[sfh].cur_size == obj_fh.fh[sfh].size) {
+                       obj_fh.fh[sfh].exist_flag = COMPLETE;
+               };
+
+#define ACCUMULATE_SMALL_WRITE 
+// This option improves speed by 12 times.
+#ifdef ACCUMULATE_SMALL_WRITE
+               obj_fh.fh[sfh].accumulated_write_size += write_size;
+               if (obj_fh.fh[sfh].exist_flag == COMPLETE) {
+                       disk_write_size = obj_fh.fh[sfh].accumulated_write_size;
+               } else {
+                       disk_write_size = (obj_fh.fh[sfh].accumulated_write_size -
+                                                         (obj_fh.fh[sfh].accumulated_write_size%DISK_FRAGMENT_SIZE));
+               };
+               obj_fh.fh[sfh].accumulated_write_size -= disk_write_size;
+#else
+               disk_write_size = write_size;
+#endif
+
+               if (disk_write_size >0) {
+                       append_file (sfh, obj_fh.fh[sfh].path, disk_write_size);
+                       if ((i%1000)==0) {
+                               printf ("%d C ", i);
+                               fflush(stdout);
+                               k++;
+                               if ((k%10)==0)
+                                       printf("\n");
+                       }
+                       i++;
+               } else {
+                       if ((j%100000)==0) {
+                               printf ("%d c ", j);
+                               fflush(stdout);
+                               k++;
+                               if ((k%10)==0)
+                                       printf("\n");
+                       }
+                       j++;
+               }
+       }
+}
+
diff --git a/TBBT/trace_play/rfs_c_age.c.trace_base b/TBBT/trace_play/rfs_c_age.c.trace_base
new file mode 100644 (file)
index 0000000..adeeca5
--- /dev/null
@@ -0,0 +1,551 @@
+#include <sys/vfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include "rfs_assert.h"
+#include "profile.h"
+#define MKDIR 1
+#define RMDIR 2
+#define CREATE 3
+#define REMOVE 4
+#define WRITE 5
+#define TRUNCATE 6
+
+#define MAX_FILES 100000
+#define MAX_DIRS  100000
+#define FILE_FH_HTABLE_SIZE MAX_FILES
+#define MAX_NAMELEN 256
+#define MAX_PLAY_PATH_SIZE 256
+#define MAX_COMMAND_LEN (MAX_PLAY_PATH_SIZE+16)
+#define NFS_MAXDATA 32768
+#define TRACE_FH_SIZE 64
+
+#define FH_T_FLAG_FREE 0
+#define FH_T_FLAG_IN_USE 1
+#define IS_FILE 0
+#define IS_DIR 1
+#define NOT_EXIST 0
+#define EXIST 1
+
+typedef struct {
+    char flag;
+    //char trace_fh [TRACE_FH_SIZE+1];
+    char path[MAX_PLAY_PATH_SIZE];
+} fh_t;
+
+typedef struct {
+       char name[32];
+       fh_t * fh;
+       //struct generic_entry * htable;
+       int fh_size;
+       int fh_max;
+       int index;
+       //int htable_size;
+} fh_info_t;
+
+fh_info_t file_fh, dir_fh;
+profile_t read_line_profile, fgets_profile;
+char trace_file[MAX_NAMELEN];
+FILE * profile_fp = NULL;
+char testdir[MAX_NAMELEN];
+
+int age_create_num = 0;
+int age_mkdir_num = 0;
+int assure_create_num = 0;
+int assure_mkdir_num = 0;
+int age_write_num = 0;
+int nonage_write_num = 0;
+int overlap_write_num = 0;
+
+int init_profile_variables()
+{
+       init_profile ("read_line profile", &read_line_profile);
+       init_profile ("fgets profile", &fgets_profile);
+}
+
+int init_fh_info (char * name, fh_info_t * fh_infop, int fh_size, int htable_size)
+{
+       RFS_ASSERT (strlen(name) < sizeof(fh_infop->name));
+       strcpy (fh_infop->name, name);
+       fh_infop->fh_max = 0;
+       fh_infop->index = 0;
+       fh_infop->fh_size = fh_size;
+       //fh_infop->htable_size = htable_size;
+       fh_infop->fh = (fh_t *)malloc (sizeof(fh_t)*fh_size);
+       RFS_ASSERT (fh_infop->fh);
+       //fh_infop->htable = malloc (sizeof(struct*generic_entry)*htable_size);
+       //RFS_ASSERT (fh_infop->htable);
+       printf("initialize %s size %d bytes\n", 
+               //name, sizeof(fh_t)*fh_size + sizeof(struct*generic_entry)*htable_size);
+               name, sizeof(fh_t)*fh_size);
+}
+
+int init()
+{
+       init_fh_info ("file_fh", &file_fh, MAX_FILES, MAX_FILES);
+       init_fh_info ("dir_fh", &dir_fh, MAX_DIRS, MAX_DIRS);
+}
+
+int add_fh_t (fh_info_t * fh_table, char * path, int exist_flag)
+{
+       int i;
+
+       for (i=0; i<fh_table->fh_size; i++,fh_table->index++) {
+               if (fh_table->index==fh_table->fh_size)
+                       fh_table->index = 0;
+               if (fh_table->fh[fh_table->index].flag == FH_T_FLAG_FREE) {
+                       fh_table->fh[fh_table->index].flag = FH_T_FLAG_IN_USE;
+                       //RFS_ASSERT(strlen(path)<MAX_PLAY_PATH_SIZE);
+                       strcpy (fh_table->fh[fh_table->index].path, path);
+                       if (fh_table->index > fh_table->fh_max)
+                               fh_table->fh_max = fh_table->index;
+                       return 0;
+               }
+       }
+       //print_fh_map(fh_table);
+       RFS_ASSERT (0);
+}
+
+int create_mkdir_op (int flag)
+{
+       static int fhno = 0;
+       char name[MAX_NAMELEN];
+       char command[MAX_COMMAND_LEN];
+       int i;
+       int fd;
+       int count = 0;
+       fh_info_t * fh_infop;
+
+       while (count++ < 100) {
+               i = random()%dir_fh.fh_max;
+               if (dir_fh.fh[i].flag==FH_T_FLAG_IN_USE) {
+                       assure_exist(dir_fh.fh[i].path);
+                       strcpy (name, dir_fh.fh[i].path);
+                       if (flag == IS_FILE) {
+                               sprintf (name+strlen(name), "AGEfile%d", fhno++);
+                               fd = creat (name, S_IRWXU);
+                               age_create_num++;
+                               //printf ("create fd %d\n", fd);
+                               close(fd);
+                               fh_infop = &file_fh;
+                       } else {
+                               sprintf (name+strlen(name), "AGEdir%d", fhno++);
+                               fd = mkdir (name, S_IRWXU);
+                               age_mkdir_num++;
+                               fh_infop = &dir_fh;
+                       }
+                       if (fd == -1) {
+                               perror("");
+                               if (errno == ENOENT) {
+                                       dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                                       continue;
+                               } else
+                                       RFS_ASSERT (0);
+                       }
+                       add_fh_t (fh_infop, name, EXIST);
+                       RFS_ASSERT (fd >=0);
+                       return 0;
+               }
+       };
+       return -1;
+}
+
+int remove_op ()
+{
+       int i;
+       int count = 0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = remove (file_fh.fh[i].path);
+                       RFS_ASSERT (ret ==0);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+int rmdir_op()
+{
+       int i;
+       int count=0;
+       char command[MAX_COMMAND_LEN];
+       int ret;
+
+       while (count++<100) {
+               i = random()%dir_fh.fh_max;
+               if ( (dir_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = rmdir (dir_fh.fh[i].path);
+                       if (ret == 0) {
+                               dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                               return 0;
+                       }
+                       RFS_ASSERT ((ret == -1) && (errno == ENOTEMPTY));
+                       //strcpy (command, "rm -r %s", dir_fh.fh[i].path);
+                       //system (command);
+               }
+       }
+       return -1;
+}
+
+int loop_write (int fd, char * buf, int buflen)
+{
+    int ret;
+    int pos = 0;
+
+    while (1) {
+        ret = write (fd, buf+pos, buflen-pos);
+
+        if (ret == -1) {
+            perror ("loop write");
+            exit (-1);
+        }
+        if (ret == buflen-pos)
+            break;
+        pos += ret;
+    }
+    return 0;
+}
+
+int assure_exist(char * path)
+{
+       char name[MAX_NAMELEN];
+       int ret;
+       char *p, *q;
+       int non_exist_flag = 0;
+       int count=0;
+       struct stat st;
+
+       ret = stat (path, &st);
+       if (ret == 0)
+               return 0;
+       RFS_ASSERT (errno == ENOENT);
+       
+       RFS_ASSERT (!strstr (path, "AGE"));
+       p = path;
+       q = name;
+       while (count++<100) {
+               for (; *p!=0 && *p!='/'; p++, q++ ) 
+                       *q = *p;
+               *q = 0;
+               ret = stat (name, &st);
+               if (ret == -1) {
+                       RFS_ASSERT (errno == ENOENT)
+                       if ((*p)==0) {
+                               ret = creat (name, S_IRWXU);
+                               assure_create_num ++;
+                               RFS_ASSERT (ret >=0);
+                               close(ret);
+                       } else {
+                               ret = mkdir (name, S_IRWXU);
+                               assure_mkdir_num ++;
+                               RFS_ASSERT (ret >=0);
+                       }
+               }
+               if ((*p)=='/') {
+                       *q = '/';
+                       p++; q++;
+               } else {
+                       RFS_ASSERT ((*p)==0)
+                       return 0;
+               }
+       }
+       RFS_ASSERT (0);
+}
+
+int write_op (int off, int size)
+{
+       static char buf[NFS_MAXDATA];
+       int i;
+       int count=0;
+       int fd;
+       int ret;
+       struct stat st;
+
+       RFS_ASSERT (size <= NFS_MAXDATA);
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+                       assure_exist(file_fh.fh[i].path);
+                       fd = open(file_fh.fh[i].path, O_WRONLY);
+                       if (fd == -1)
+                               perror("");
+                       //else 
+                               //printf ("write fd %d\n", fd);
+                       RFS_ASSERT (fd!=-1);
+                       fstat (fd, &st);
+                       if (st.st_size < (off+size)) {
+                               int written_bytes = 0;
+                               while (written_bytes+NFS_MAXDATA < off+size-st.st_size) {
+                                       loop_write (fd, buf, NFS_MAXDATA);
+                                       written_bytes += NFS_MAXDATA;
+                               }
+                               loop_write (fd, buf, off+size-st.st_size-written_bytes);
+                               if (strstr(file_fh.fh[i].path, "AGE")) {
+                                       age_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                               } else 
+                                       nonage_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                       } else
+                               overlap_write_num++;
+/*
+                       if (strstr(file_fh.fh[i].path, "AGE")) {
+                               age_write_num++;
+                       } else 
+                               nonage_write_num++;
+                       loop_write (fd, buf, size);
+*/
+                       close(fd);
+                       return 0;
+               };
+       }
+       return -1;
+}
+
+int truncate_op(int size)
+{
+       int i;
+       int count=0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist (file_fh.fh[i].path);
+                       ret = truncate(file_fh.fh[i].path, size);
+                       if (ret ==0) 
+                               return 0;
+                       RFS_ASSERT (errno == ENOENT);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       continue;       
+               }
+       };
+       return -1;
+}
+
+int print_fh_map(fh_info_t * fhp)
+{
+       int i;
+       int num = 0;
+       for (i=0; i<fhp->fh_max; i++) {
+               if (fhp->fh[i].flag == FH_T_FLAG_IN_USE) {
+                       num ++;
+                       printf("%s[%d] %s\n", fhp->name, i, fhp->fh[i].path);
+               }
+       }
+       fprintf(stderr, "fh_max %d total %d entries \n", fhp->fh_max, num);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+       int lineno = 0;
+       int fh_map_debug =0;
+       char name[MAX_NAMELEN];
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               RFS_ASSERT (fh_map_debug==0);
+               lineno ++;
+               if (lineno % 10000==0)
+                       printf("%d fh_map entry read\n", lineno);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+
+               trace_path = buf + TRACE_FH_SIZE +1;
+
+               strcpy (name, testdir);
+               strcat (name, trace_path);
+               if ((*(buf+strlen(buf)-1))=='/') {
+                       *(buf+strlen(buf)-1)=0;
+                       add_fh_t (&dir_fh, name, NOT_EXIST);
+               } else {
+                       add_fh_t (&file_fh, name, NOT_EXIST);
+               }
+       }
+                       
+       fclose(fp);
+       if (fh_map_debug) {
+               print_fh_map (&file_fh);
+               print_fh_map (&dir_fh);
+       }
+}
+
+int print_usage()
+{
+       printf("age trace_file fh_path_map testdir\n");
+}
+
+inline char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+
+#define READ_LINE_BUF_SIZE 1000
+#define READ_LINE_LENGTH 32
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                               RFS_ASSERT (0);
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       fclose(fp);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+int f()
+{};
+
+int print_result()
+{
+       struct statfs stfs;
+       int ret;
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       fprintf(stderr, "number of files %d size of file system %d\n", stfs.f_files, stfs.f_bfree);
+       fprintf(stderr, "assure_create_num %d assure_mkdir_num %d, age_create_num %d age_mkdir_num %d age_write_num %d nonage_write_num %d overlap_write_num %d\n",
+                       assure_create_num, assure_mkdir_num, age_create_num, age_mkdir_num, age_write_num, nonage_write_num, overlap_write_num);
+       printf("assure_create_num %d assure_mkdir_num %d, age_create_num %d age_mkdir_num %d age_write_num %d nonage_write_num %d overlap_write_num %d\n",
+                       assure_create_num, assure_mkdir_num, age_create_num, age_mkdir_num, age_write_num, nonage_write_num, overlap_write_num);
+}
+
+int main(int argc, char ** argv)
+{
+       char * buf;
+       static int disk_index=0;
+       int j, nfs3proc, size, off, count;
+       char procname[16];
+       struct stat st;
+       int ret;
+
+       if (argc!=4) {
+               print_usage();
+               exit(0);
+       }
+
+       init();
+       strcpy (trace_file, argv[1]);
+       strcpy (testdir, argv[3]);
+       ret = stat (testdir, &st);
+       RFS_ASSERT (ret == 0);
+       read_fh_map(argv[2]);
+       init_profile_variables();
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+
+               memset (procname, 0, sizeof(procname));
+               //printf ("line[%d] %s", disk_index, buf);
+               sscanf (&buf[0], "%s", procname);
+               j = 0;
+               while ((*(buf+j)!=' ') && (*(buf+j)!='\n'))
+                       j++;
+               j++;
+               if (!strcmp(procname, "write"))
+                       sscanf (&buf[j], "off %x count %x", &off, &count);
+
+               if (!strcmp(procname, "setattr")) 
+                       sscanf (&buf[j], "size %x", &size);
+
+               if (!strcmp(procname, "write"))
+                       ret = write_op(off, count);
+               else if (!strcmp(procname, "create")) 
+                       ret = create_mkdir_op(IS_FILE); 
+               else if (!strcmp(procname, "mkdir")) 
+                       ret = create_mkdir_op(IS_DIR);
+               else if (!strcmp(procname, "remove")) 
+                       ret = remove_op(); 
+               else if (!strcmp(procname, "rmdir")) 
+                       ret = rmdir_op();
+               else if (!strcmp(procname, "setattr")) 
+                       ret = truncate_op(size);
+               else {
+                       printf("disk_index %d procname %s\n", disk_index, procname);
+                       RFS_ASSERT (0);
+               }
+               if (ret!=0) {
+                       printf("execute disk_line[%d] %s error\n", disk_index, buf);
+               }
+               if ((disk_index%100)==0) {
+                       fprintf (stderr, "%d disk trace parsed \n", disk_index);
+                       print_result();
+               }
+       }
+       print_result();
+}
diff --git a/TBBT/trace_play/rfs_c_age.c.unit_base b/TBBT/trace_play/rfs_c_age.c.unit_base
new file mode 100644 (file)
index 0000000..176ad54
--- /dev/null
@@ -0,0 +1,915 @@
+/* rfs_age_unit_base.c */
+#include <sys/vfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include "rfs_assert.h"
+#include "profile.h"
+#define MKDIR 1
+#define RMDIR 2
+#define CREATE 3
+#define REMOVE 4
+#define WRITE 5
+#define TRUNCATE 6
+
+#define MAX_FILES 100000
+#define MAX_DIRS  100000
+#define FILE_FH_HTABLE_SIZE MAX_FILES
+#define MAX_NAMELEN 512
+#define MAX_PLAY_PATH_SIZE 1024
+#define MAX_COMMAND_LEN (MAX_PLAY_PATH_SIZE+16)
+#define NFS_MAXDATA 4096
+//#define NFS_MAXDATA 32768
+#define TRACE_FH_SIZE 64
+
+#define FH_T_FLAG_FREE 0
+#define FH_T_FLAG_IN_USE 1
+#define IS_FILE 0
+#define IS_DIR 1
+#define EXIST 0
+#define NON_EXIST 1
+#define COMPLETE 3
+#define ACTIVE 0
+#define INACTIVE 1
+#define DONT_CARE 2
+#define FILE_RATIO 50
+#define DISK_FRAGMENT_SIZE 4096
+//#define FRAGMENT_NUM 5
+//#define MIN_WRITE_SIZE 512
+//#define MIN_WRITE_SIZE 2000000000
+
+static char ftypename[3][32] = {"FILE", "DIR", "FTYPE_DONT_CARE"};
+static char activename[3][32] = {"ACTIVE", "INACTIVE", "ACTIVE_DONT_CARE"};
+static char existname[4][32] = {"EXIST", "NON_EXIST", "EXIST_DONT_CARE", "COMPLETE"};
+
+typedef struct {
+    char flag;
+       char ftype;
+       char exist_flag;
+       int psfh;
+       int size;
+       int cur_size;
+    //char trace_fh [TRACE_FH_SIZE+1];
+    char path[MAX_PLAY_PATH_SIZE];
+} fh_t;
+
+typedef struct {
+       char name[32];
+       fh_t * fh;
+       //struct generic_entry * htable;
+       int fh_size;
+       int fh_max;
+       int active_fh_max;
+       //int index;
+       //int htable_size;
+} fh_info_t;
+
+fh_info_t obj_fh;
+profile_t read_line_profile, fgets_profile;
+char trace_file[MAX_NAMELEN];
+FILE * profile_fp = NULL;
+char testdir[MAX_NAMELEN];
+
+int active_obj_num = 0;
+int exist_active_obj_num = 0;
+static int active_file_num = 0, active_dir_num =0, age_file_num = 0, age_dir_num = 0;
+
+int age_create_num = 0;
+int age_mkdir_num = 0;
+int assure_create_num = 0;
+int assure_mkdir_num = 0;
+int age_write_num = 0;
+int nonage_write_num = 0;
+int overlap_write_num = 0;
+
+int rfs_debug = 0;
+
+
+int ACTIVE_RATIO;
+int FRAGMENT_NUM;
+int MIN_WRITE_SIZE = 512;
+
+int aging_dirs ()
+{
+
+}
+
+
+int init_profile_variables()
+{
+       init_profile ("read_line profile", &read_line_profile);
+       init_profile ("fgets profile", &fgets_profile);
+}
+
+int init_fh_info (char * name, fh_info_t * fh_infop, int fh_size, int htable_size)
+{
+       int i;
+
+       RFS_ASSERT (strlen(name) < sizeof(fh_infop->name));
+       strcpy (fh_infop->name, name);
+       fh_infop->fh_max = 0;
+       //fh_infop->index = 0;
+       fh_infop->fh_size = fh_size;
+       //fh_infop->htable_size = htable_size;
+       fh_infop->fh = (fh_t *)malloc (sizeof(fh_t)*fh_size);
+       RFS_ASSERT (fh_infop->fh);
+       //fh_infop->htable = malloc (sizeof(struct*generic_entry)*htable_size);
+       //RFS_ASSERT (fh_infop->htable);
+       printf("initialize %s size %d bytes\n", 
+               //name, sizeof(fh_t)*fh_size + sizeof(struct*generic_entry)*htable_size);
+               name, sizeof(fh_t)*fh_size);
+
+       for (i=0; i<fh_size; i++)
+               fh_infop->fh[i].flag = FH_T_FLAG_FREE;
+}
+
+int init()
+{
+//     init_fh_info ("file_fh", &file_fh, MAX_FILES, MAX_FILES);
+//     init_fh_info ("dir_fh", &dir_fh, MAX_DIRS, MAX_DIRS);
+       init_fh_info ("obj_fh", &obj_fh, MAX_FILES+MAX_DIRS, MAX_FILES+MAX_DIRS);
+}
+
+int add_fh_t (fh_info_t * fh_table, char * path, int sfh, int psfh, int size, int ftype, int exist_flag, int active_flag)
+{
+       int i;
+
+       RFS_ASSERT (sfh >0);
+
+       if (active_flag == ACTIVE)
+               active_obj_num ++;
+       else
+               RFS_ASSERT (sfh >= fh_table->active_fh_max);
+
+       if (rfs_debug)
+               printf ("add to %s path %s sfh %d size %d %s %s %s\n", fh_table->name, path, sfh, size, 
+               ftypename[ftype], existname[exist_flag], activename[active_flag]);
+
+       RFS_ASSERT ( (sfh>=0) && (sfh<fh_table->fh_size) );
+       RFS_ASSERT (fh_table->fh[sfh].flag==FH_T_FLAG_FREE);
+       fh_table->fh[sfh].flag = FH_T_FLAG_IN_USE;
+       if (sfh >= fh_table->fh_max)
+               fh_table->fh_max = sfh+1;
+       strcpy (fh_table->fh[sfh].path, path);
+       fh_table->fh[sfh].psfh = psfh;
+       fh_table->fh[sfh].size = size;
+       fh_table->fh[sfh].cur_size = 0;
+       fh_table->fh[sfh].ftype = ftype;
+       fh_table->fh[sfh].exist_flag = exist_flag;
+       if (active_flag == ACTIVE) {
+               if (ftype == IS_FILE)
+                       active_file_num ++;
+               else {
+                       RFS_ASSERT (ftype== IS_DIR);
+                       active_dir_num ++;
+               }
+       } else {
+               if (ftype == IS_FILE)
+                       age_file_num ++;
+               else {
+                       RFS_ASSERT (ftype== IS_DIR);
+                       age_dir_num ++;
+               }
+       }
+       //print_fh_map(fh_table);
+}
+
+
+int loop_write (int fd, char * buf, int buflen)
+{
+    int ret;
+    int pos = 0;
+
+    while (1) {
+        ret = write (fd, buf+pos, buflen-pos);
+
+        if (ret == -1) {
+                       printf ("fd %d\n", fd);
+            perror ("loop write");
+            exit (-1);
+        }
+        if (ret == buflen-pos)
+            break;
+        pos += ret;
+    }
+    return 0;
+}
+
+int assure_exist(int sfh, char * path, int ftype_flag)
+{
+       char name[MAX_NAMELEN];
+       int ret;
+       char *p, *q;
+       int non_exist_flag = 0;
+       int count=0;
+       struct stat st;
+
+       if (rfs_debug)
+               printf("assure_exist %s\n", path);
+
+       ret = stat (path, &st);
+       if (ret == 0)
+               return 0;
+       RFS_ASSERT (errno == ENOENT);
+       
+       p = path;
+       q = name;
+       if (*p=='/') {
+               *q='/';
+               p++;
+               q++;
+       }
+       while (count++<100) {
+               /* copy the next component from path to name */
+               for (; *p!=0 && *p!='/'; p++, q++ ) 
+                       *q = *p;
+               *q = 0;
+               ret = stat (name, &st);
+               if (ret == -1) {
+                       RFS_ASSERT (errno == ENOENT)
+                       if ((*p)==0 && (ftype_flag==IS_FILE)) {
+                               ret = creat (name, S_IRWXU);
+                               if (ret == -1)
+                                       perror (name);
+                               RFS_ASSERT (ret >=0);
+                               assure_create_num ++;
+                               if (rfs_debug)
+                                       printf("sfh %d create %s\n", sfh, name);
+                               close(ret);
+                       } else {
+                               ret = mkdir (name, S_IRWXU);
+                               assure_mkdir_num ++;
+                               if (rfs_debug) {
+                                       if (*p==0) 
+                                               printf("sfh %d mkdir %s\n", sfh, name);
+                                       else
+                                               printf("sfh %d middle mkdir %s\n", sfh, name);
+                               }
+                               RFS_ASSERT (ret >=0);
+                       }
+               }
+               if ((*p)=='/') {
+                       *q = '/';
+                       p++; q++;
+               } else {
+                       RFS_ASSERT ((*p)==0)
+                       return 0;
+               }
+       }
+       RFS_ASSERT (0);
+}
+
+
+int print_fh_map(fh_info_t * fhp)
+{
+       int i;
+       int num = 0;
+       int active_obj_num = 0;
+
+
+       for (i=0; i<fhp->fh_max; i++) {
+               if (fhp->fh[i].flag == FH_T_FLAG_IN_USE) {
+                       num ++;
+                       if (i < fhp->active_fh_max)
+                               active_obj_num++;
+
+                       if (rfs_debug)
+                               printf("%s[%d] %s %s %s\n", fhp->name, i, fhp->fh[i].path, ftypename[fhp->fh[i].ftype], existname[fhp->fh[i].exist_flag]);
+               }
+       }
+       fprintf(stderr, "fh_max %d active_fh_max %d, in_use_num %d entries active_obj_num %d \n", fhp->fh_max, fhp->active_fh_max, num, active_obj_num);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+       int lineno = 0;
+       int fh_map_debug =0;
+       char name[MAX_NAMELEN];
+       int sfh;
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               RFS_ASSERT (fh_map_debug==0);
+               lineno ++;
+               if (rfs_debug)
+                       printf ("line %d %s", lineno, buf);
+               if (lineno % 10000==0)
+                       printf("%d fh_map entry read\n", lineno);
+
+               sfh = 0;
+               if (!strncmp(buf, "::DIR ", strlen("::DIR "))) {
+                       strcpy (name, testdir);
+                       if (buf[6]=='/') {
+                               sscanf(buf, "::DIR %s %d\n", name+strlen(name), &sfh);
+                               add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, NON_EXIST, ACTIVE);
+                       } else { 
+                               RFS_ASSERT (!strncmp(buf,"::DIR Fake 1\n", strlen("::DIR Fake 1\n")));
+                               sfh = 1;
+                               add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, EXIST, ACTIVE);
+                               exist_active_obj_num ++;
+                       }
+               } else {
+                       char * p;
+                       int psfh, sfh, size;
+                       char filename[MAX_NAMELEN];
+
+                       if (!strncmp(buf, "::TBDIR", strlen("::TBDIR"))) 
+                               continue; 
+
+                       p = strstr(buf, "parent");
+                       RFS_ASSERT (p);
+                       sscanf(p, "parent %d\n", &psfh);
+                       RFS_ASSERT (obj_fh.fh[psfh].flag == FH_T_FLAG_IN_USE);
+                       p = strstr(p, "name");
+                       RFS_ASSERT (p);
+                       if (!strncmp(p, "name xx", strlen("name xx"))) {
+                               sscanf(p, "name xx-%s sfh %d size %x", filename, &sfh, &size);
+                               //printf ("name xx-%s sfh %d\n", filename, sfh);
+                       } else {
+                               sscanf(p, "name \"%s sfh %d size %x", filename, &sfh, &size);
+                               //printf ("name %s sfh %d\n", filename, sfh);
+                               filename[strlen(filename)-1]=0;
+                       }
+                       strcpy (name, obj_fh.fh[psfh].path);    
+                       strcat (name, "/");
+                       strcat (name, filename);
+                       add_fh_t (&obj_fh, name, sfh, psfh, size, IS_FILE, NON_EXIST, ACTIVE);
+               }
+       }
+                       
+       fclose(fp);
+       obj_fh.active_fh_max  = obj_fh.fh_max;
+       if (fh_map_debug) {
+               print_fh_map (&obj_fh);
+       }
+}
+
+int print_usage()
+{
+       printf("agefs ACTIVE_RATIO FRAGMENT_NUM fh_path_map testdir\n");
+       printf("Note: if populate_scale is 4, the total active file size is 1GB\n");
+       printf("      then the total initial file system size is about 4GB\n");
+}
+
+inline char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+
+#define READ_LINE_BUF_SIZE 1000
+#define READ_LINE_LENGTH 32
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                               RFS_ASSERT (0);
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       fclose(fp);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+int f()
+{};
+
+int print_result()
+{
+       struct statfs stfs;
+       int ret;
+       static struct statfs first_stfs;
+       static int first_entry = 1;
+
+       ret = statfs (testdir, &stfs);
+       RFS_ASSERT (ret == 0);
+       if (first_entry) {
+               first_entry = 0;
+               first_stfs = stfs;
+       }
+
+       fprintf(stderr, "active_file_num %d active_dir_num %d age_file_num %d age_dir_num %d\n",
+               active_file_num, active_dir_num, age_file_num, age_dir_num);
+       fprintf(stderr, "number of used file nodes %d, used (4K) blocks in fs %d (%d MB)\n", first_stfs.f_ffree-stfs.f_ffree, first_stfs.f_bfree - stfs.f_bfree, (first_stfs.f_bfree-stfs.f_bfree)/(1000000/4096));
+       fprintf(stderr, "assure_create_num %d assure_mkdir_num %d\n", assure_create_num, assure_mkdir_num);
+}
+
+typedef struct {
+    int     pcnt;       /* percentile */
+    int     size;       /* file size in KB */
+} sfs_io_file_size_dist;
+
+sfs_io_file_size_dist Default_file_size_dist[] = {
+    /* percentage   KB size */
+    {    94,     64},           /*  4% */
+    {    97,    128},           /*  3% */
+#ifdef notdef
+    {    33,      1},           /* 33% */
+    {    54,      2},           /* 21% */
+    {    67,      4},           /* 13% */
+    {    77,      8},           /* 10% */
+    {    85,     16},           /*  8% */
+    {    90,     32},           /*  5% */
+    {    94,     64},           /*  4% */
+    {    97,    128},           /*  3% */
+#endif
+    {    99,    256},           /*  2% */
+    {   100,   1024},           /*  1% */
+    {     0,      0}
+};
+
+/*
+ * For a value between 0-99, return a size based on distribution
+ */
+static int
+get_file_size()
+{
+       static file_array_initialized = 0;
+       static int file_size_array[100];
+       int i;
+
+       i = random() % 100;
+
+    if (i < 0 || i > 99)
+    return (0);
+
+    if (file_array_initialized == 0) {
+           int j, k;
+       for (j = 0, k = 0; j < 100; j++) {
+               if (j >= Default_file_size_dist[k].pcnt &&
+               Default_file_size_dist[k + 1].size != 0)
+           k++;
+               file_size_array[j] = Default_file_size_dist[k].size * 1024;
+       }
+       file_array_initialized++;
+    }
+    return (file_size_array[i]);
+}
+
+int range_random(int min, int max)
+{
+       int i;
+       i = random()%(max-min) + min;
+       return i;
+}
+
+/* answer 1 with a probability of percent/100 */
+int decide(int percent)
+{
+       int i = random()%100;
+       if (i<percent)
+               return 1;
+       else
+               return 0;
+}
+
+int select_obj (fh_info_t * fhp, int ftype, int exist_flag, int active_flag)
+{
+       int i;
+       int min, max;
+       int sfh, count = 0;
+
+       //printf ("select_obj %s %s %s\n", ftypename[ftype], existname[exist_flag], activename[active_flag]);
+       if (active_flag == ACTIVE) {
+               sfh = range_random (0, fhp->active_fh_max);
+               for (i=0; i<fhp->active_fh_max; i++) {
+                       if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
+                               ((ftype==DONT_CARE) || (ftype ==fhp->fh[sfh].ftype)) &&
+                               ((exist_flag==DONT_CARE) || (fhp->fh[sfh].exist_flag == exist_flag))) 
+                               return sfh;
+                       sfh = (sfh+1) % fhp->active_fh_max;
+               }
+       } else {
+               RFS_ASSERT (active_flag == DONT_CARE);
+               RFS_ASSERT (exist_flag == EXIST);
+               sfh = range_random (0, fhp->fh_max);
+               for (i=0; i<fhp->fh_max; i++) {
+                       if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
+                           ((ftype==DONT_CARE) || (fhp->fh[sfh].ftype == ftype)) &&
+                               (fhp->fh[sfh].exist_flag == EXIST)) {
+                               return sfh;
+                       }
+                       sfh = (sfh+1) % fhp->fh_max;
+               }
+       }
+       return -1;
+
+       print_fh_map(&obj_fh);
+       printf ("active_obj_num %d exist_active_obj_num %d \n", active_obj_num, exist_active_obj_num);
+       printf ("failed select_obj %s %s\n", ftypename[ftype], activename[active_flag]);
+       RFS_ASSERT (0);
+}
+
+/* append "size" to file "path" */
+int append_file (int sfh, char * path, int size)
+{
+       int fd;
+       int written_bytes = 0;
+       static char buf[NFS_MAXDATA];
+
+       if (rfs_debug)
+               printf ("sfh %d append_file %s size %d\n", sfh, path, size);
+
+       fd = open (path, O_WRONLY|O_APPEND);
+       if (fd==-1)
+               perror(path);
+       RFS_ASSERT (fd > 0);
+       
+       while (written_bytes+NFS_MAXDATA < size) {
+               loop_write (fd, buf, NFS_MAXDATA);
+               written_bytes += NFS_MAXDATA;
+       }
+       loop_write (fd, buf, size-written_bytes);
+       close(fd);
+}
+
+int get_write_size (int target_size, int cur_size)
+{
+       int i;
+       if (target_size - cur_size < MIN_WRITE_SIZE)
+               return (target_size - cur_size);
+
+       /* target_size/FRAGMENT_NUM would be the average value of i */
+       if (target_size < FRAGMENT_NUM) {
+               i = MIN_WRITE_SIZE;
+       } else {
+               i = random() % (2*(target_size/FRAGMENT_NUM));
+               if (i < MIN_WRITE_SIZE)
+                       i = MIN_WRITE_SIZE;
+       }
+       if (i > (target_size - cur_size))
+               i = target_size - cur_size;
+
+       return i;
+}
+
+int main(int argc, char ** argv)
+{
+       char * buf;
+       static int disk_index=0;
+       int j, nfs3proc, size, off, count;
+       char procname[16];
+       struct stat st;
+       int ret;
+       int i;
+       int ftype_flag = 0, active_flag = 0;
+       char name[MAX_PLAY_PATH_SIZE];  
+       int sfh, psfh;
+
+       if (argc!=5) {
+               print_usage();
+               exit(0);
+       }
+
+       init();
+       ACTIVE_RATIO = atoi(argv[1]);
+       FRAGMENT_NUM = atoi(argv[2]);
+       if (FRAGMENT_NUM==0)
+               MIN_WRITE_SIZE = 2000000000;
+       else
+               MIN_WRITE_SIZE = DISK_FRAGMENT_SIZE;
+
+       strcpy (testdir, argv[4]);
+       ret = stat (testdir, &st);
+       if ((ret == -1) && (errno==ENOENT)) {
+               ret = mkdir (testdir, S_IRWXU);
+       }
+       RFS_ASSERT (ret >= 0);
+       read_fh_map(argv[3]);
+       print_fh_map(&obj_fh);
+       init_profile_variables();
+
+/* NOTE: should have put file and directories in one table */
+
+       for (i=0; exist_active_obj_num < active_obj_num; i++) {
+
+               if ((i!=0) && ((i%1000)==0)) {
+                       fprintf (stderr, "\n%d object created \n", i);
+                       print_result();
+               }
+
+               /* decide on the exact active obj or populated obj */
+               if (decide(ACTIVE_RATIO)) {
+                       sfh = select_obj (&obj_fh, DONT_CARE, NON_EXIST, ACTIVE);
+                       if (sfh == -1)
+                               break;
+
+                       obj_fh.fh[sfh].exist_flag = EXIST;
+                       exist_active_obj_num ++;
+                       ftype_flag = obj_fh.fh[sfh].ftype;
+                       size = obj_fh.fh[sfh].size;
+
+/*
+                       {
+                               int tmpfh = sfh;
+                               while (obj_fh.fh[--tmpfh].exist_flag == NON_EXIST) {
+                                       if (strstr(obj_fh.fh[sfh].path, obj_fh.fh[tmpfh].path)) {
+                                               obj_fh.fh[tmpfh].exist_flag = EXIST;
+                                               //printf ("set %s to exist due to %s\n", obj_fh.fh[tmpfh].path, obj_fh.fh[sfh].path);
+                                               exist_active_obj_num ++;
+                                       }
+                               }       
+                       }
+*/
+               } else {
+                       psfh = select_obj (&obj_fh, IS_DIR, EXIST, DONT_CARE);
+                       strcpy (name, obj_fh.fh[psfh].path);
+                       sfh = obj_fh.fh_max;
+                       sprintf(name+strlen(name), "/AGE%d", obj_fh.fh_max); 
+
+                       /* decide next obj is file or directory */
+                       if (decide(FILE_RATIO)) {
+                               ftype_flag = IS_FILE;
+                               size = get_file_size();
+                       } else {
+                               ftype_flag = IS_DIR;
+                               size = -1;
+                       }
+                       add_fh_t (&obj_fh, name, sfh, psfh, size, ftype_flag, EXIST, INACTIVE);
+
+               }
+
+               /* make sure/create the  obj pathname on disk */
+               assure_exist (sfh, obj_fh.fh[sfh].path, ftype_flag);
+               /* write file to sizes according certain distribution 
+               if (ftype_flag == IS_FILE) 
+                       append_file (obj_fh.fh[sfh].path, obj_fh.fh[sfh].size);
+               */
+
+       }
+
+       i = 0;
+       printf ("start writing files\n");
+       while (1) {
+               int write_size;
+               sfh = select_obj (&obj_fh, IS_FILE, EXIST, DONT_CARE);
+               if (sfh == -1)
+                       break;
+               write_size = get_write_size (obj_fh.fh[sfh].size, obj_fh.fh[sfh].cur_size);
+               append_file (sfh, obj_fh.fh[sfh].path, write_size);
+               obj_fh.fh[sfh].cur_size += write_size;
+               if (obj_fh.fh[sfh].cur_size == obj_fh.fh[sfh].size) {
+                       obj_fh.fh[sfh].exist_flag = COMPLETE;
+               }
+               if ((i%100)==0)
+                       printf ("%d append_file operation performed\n", i);
+               i++;
+       }
+
+       printf ("end of file system object creation\n");
+       print_fh_map(&obj_fh);
+       print_result();
+}
+
+#ifdef notdef
+int create_mkdir_op (int flag)
+{
+       static int fhno = 0;
+       char name[MAX_NAMELEN];
+       char command[MAX_COMMAND_LEN];
+       int i;
+       int fd;
+       int count = 0;
+       fh_info_t * fh_infop;
+
+       while (count++ < 100) {
+               i = random()%dir_fh.fh_max;
+               if (dir_fh.fh[i].flag==FH_T_FLAG_IN_USE) {
+                       assure_exist(dir_fh.fh[i].path);
+                       strcpy (name, dir_fh.fh[i].path);
+                       if (flag == IS_FILE) {
+                               sprintf (name+strlen(name), "AGEfile%d", fhno++);
+                               fd = creat (name, S_IRWXU);
+                               age_create_num++;
+                               //printf ("create fd %d\n", fd);
+                               close(fd);
+                               fh_infop = &file_fh;
+                       } else {
+                               sprintf (name+strlen(name), "AGEdir%d", fhno++);
+                               fd = mkdir (name, S_IRWXU);
+                               age_mkdir_num++;
+                               fh_infop = &dir_fh;
+                       }
+                       if (fd == -1) {
+                               perror("");
+                               if (errno == ENOENT) {
+                                       dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                                       continue;
+                               } else
+                                       RFS_ASSERT (0);
+                       }
+                       add_fh_t (fh_infop, name, EXIST);
+                       RFS_ASSERT (fd >=0);
+                       return 0;
+               }
+       };
+       return -1;
+}
+
+int remove_op ()
+{
+       int i;
+       int count = 0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = remove (file_fh.fh[i].path);
+                       RFS_ASSERT (ret ==0);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+int rmdir_op()
+{
+       int i;
+       int count=0;
+       char command[MAX_COMMAND_LEN];
+       int ret;
+
+       while (count++<100) {
+               i = random()%dir_fh.fh_max;
+               if ( (dir_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = rmdir (dir_fh.fh[i].path);
+                       if (ret == 0) {
+                               dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                               return 0;
+                       }
+                       RFS_ASSERT ((ret == -1) && (errno == ENOTEMPTY));
+                       //strcpy (command, "rm -r %s", dir_fh.fh[i].path);
+                       //system (command);
+               }
+       }
+       return -1;
+}
+
+int write_op (int off, int size)
+{
+       static char buf[NFS_MAXDATA];
+       int i;
+       int count=0;
+       int fd;
+       int ret;
+       struct stat st;
+
+       RFS_ASSERT (size <= NFS_MAXDATA);
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+                       assure_exist(file_fh.fh[i].path);
+                       fd = open(file_fh.fh[i].path, O_WRONLY);
+                       if (fd == -1)
+                               perror("");
+                       //else 
+                               //printf ("write fd %d\n", fd);
+                       RFS_ASSERT (fd!=-1);
+                       fstat (fd, &st);
+                       if (st.st_size < (off+size)) {
+                               int written_bytes = 0;
+                               while (written_bytes+NFS_MAXDATA < off+size-st.st_size) {
+                                       loop_write (fd, buf, NFS_MAXDATA);
+                                       written_bytes += NFS_MAXDATA;
+                               }
+                               loop_write (fd, buf, off+size-st.st_size-written_bytes);
+                               if (strstr(file_fh.fh[i].path, "AGE")) {
+                                       age_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                               } else 
+                                       nonage_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                       } else
+                               overlap_write_num++;
+/*
+                       if (strstr(file_fh.fh[i].path, "AGE")) {
+                               age_write_num++;
+                       } else 
+                               nonage_write_num++;
+                       loop_write (fd, buf, size);
+*/
+                       close(fd);
+                       return 0;
+               };
+       }
+       return -1;
+}
+
+int truncate_op(int size)
+{
+       int i;
+       int count=0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist (file_fh.fh[i].path);
+                       ret = truncate(file_fh.fh[i].path, size);
+                       if (ret ==0) 
+                               return 0;
+                       RFS_ASSERT (errno == ENOENT);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       continue;       
+               }
+       };
+       return -1;
+}
+
+int aging_files ()
+{
+       char name[MAX_NAMELEN];
+       int sfh;        /* file to be aged */
+       int psfh;
+       int ret;
+       struct stat st;
+       int agefd;
+
+       /* get the sfh and size of the selected file to be aged */
+       sfh = select_obj (&obj_fh, IS_FILE, EXIST, ACTIVE);
+       ret = stat (obj_fh.fh[sfh].path, &st);
+       RFS_ASSERT (ret == 0);
+       ret = truncate(obj_fh.fh[i].path, st.st_size/2);
+       RFS_ASSERT (ret==0);
+
+       psfh = obj_fh.fh[sfh].psfh;
+       strcpy (name, obj_fh.fh[psfh].path);
+       sprintf(name+strlen(name), "/AGE%d", obj_fh.fh_max); 
+       agefd = creat (name, S_IRWXU);
+       //write (agefs, buf, 0);
+
+       add_fh_t (&obj_fh, name, sfh, psfh, size, ftype_flag, EXIST, INACTIVE);
+}
+#endif
diff --git a/TBBT/trace_play/rfs_c_age.obsolete.c b/TBBT/trace_play/rfs_c_age.obsolete.c
new file mode 100644 (file)
index 0000000..aab4644
--- /dev/null
@@ -0,0 +1,194 @@
+#ifdef notdef
+int create_mkdir_op (int flag)
+{
+       static int fhno = 0;
+       char name[MAX_NAMELEN];
+       char command[MAX_COMMAND_LEN];
+       int i;
+       int fd;
+       int count = 0;
+       fh_info_t * fh_infop;
+
+       while (count++ < 100) {
+               i = random()%dir_fh.fh_max;
+               if (dir_fh.fh[i].flag==FH_T_FLAG_IN_USE) {
+                       assure_exist(dir_fh.fh[i].path);
+                       strcpy (name, dir_fh.fh[i].path);
+                       if (flag == IS_FILE) {
+                               sprintf (name+strlen(name), "AGEfile%d", fhno++);
+                               fd = creat (name, S_IRWXU);
+                               age_create_num++;
+                               //printf ("create fd %d\n", fd);
+                               close(fd);
+                               fh_infop = &file_fh;
+                       } else {
+                               sprintf (name+strlen(name), "AGEdir%d", fhno++);
+                               fd = mkdir (name, S_IRWXU);
+                               age_mkdir_num++;
+                               fh_infop = &dir_fh;
+                       }
+                       if (fd == -1) {
+                               perror("");
+                               if (errno == ENOENT) {
+                                       dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                                       continue;
+                               } else
+                                       RFS_ASSERT (0);
+                       }
+                       add_fh_t (fh_infop, name, EXIST);
+                       RFS_ASSERT (fd >=0);
+                       return 0;
+               }
+       };
+       return -1;
+}
+
+int remove_op ()
+{
+       int i;
+       int count = 0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = remove (file_fh.fh[i].path);
+                       RFS_ASSERT (ret ==0);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+int rmdir_op()
+{
+       int i;
+       int count=0;
+       char command[MAX_COMMAND_LEN];
+       int ret;
+
+       while (count++<100) {
+               i = random()%dir_fh.fh_max;
+               if ( (dir_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist(file_fh.fh[i].path);
+                       ret = rmdir (dir_fh.fh[i].path);
+                       if (ret == 0) {
+                               dir_fh.fh[i].flag = FH_T_FLAG_FREE;
+                               return 0;
+                       }
+                       RFS_ASSERT ((ret == -1) && (errno == ENOTEMPTY));
+                       //strcpy (command, "rm -r %s", dir_fh.fh[i].path);
+                       //system (command);
+               }
+       }
+       return -1;
+}
+
+int write_op (int off, int size)
+{
+       static char buf[NFS_MAXDATA];
+       int i;
+       int count=0;
+       int fd;
+       int ret;
+       struct stat st;
+
+       RFS_ASSERT (size <= NFS_MAXDATA);
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+                       assure_exist(file_fh.fh[i].path);
+                       fd = open(file_fh.fh[i].path, O_WRONLY);
+                       if (fd == -1)
+                               perror("");
+                       //else 
+                               //printf ("write fd %d\n", fd);
+                       RFS_ASSERT (fd!=-1);
+                       fstat (fd, &st);
+                       if (st.st_size < (off+size)) {
+                               int written_bytes = 0;
+                               while (written_bytes+NFS_MAXDATA < off+size-st.st_size) {
+                                       loop_write (fd, buf, NFS_MAXDATA);
+                                       written_bytes += NFS_MAXDATA;
+                               }
+                               loop_write (fd, buf, off+size-st.st_size-written_bytes);
+                               if (strstr(file_fh.fh[i].path, "AGE")) {
+                                       age_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                               } else 
+                                       nonage_write_num+=(written_bytes+NFS_MAXDATA-1)/NFS_MAXDATA;
+                       } else
+                               overlap_write_num++;
+/*
+                       if (strstr(file_fh.fh[i].path, "AGE")) {
+                               age_write_num++;
+                       } else 
+                               nonage_write_num++;
+                       loop_write (fd, buf, size);
+*/
+                       close(fd);
+                       return 0;
+               };
+       }
+       return -1;
+}
+
+int truncate_op(int size)
+{
+       int i;
+       int count=0;
+       int ret;
+
+       while (count++<100) {
+               i = random()%file_fh.fh_max;
+               if ( (file_fh.fh[i].flag == FH_T_FLAG_IN_USE) ) {
+/*
+                       if (!strstr(file_fh.fh[i].path, "AGE"))
+                               continue;
+*/
+                       assure_exist (file_fh.fh[i].path);
+                       ret = truncate(file_fh.fh[i].path, size);
+                       if (ret ==0) 
+                               return 0;
+                       RFS_ASSERT (errno == ENOENT);
+                       file_fh.fh[i].flag = FH_T_FLAG_FREE;
+                       continue;       
+               }
+       };
+       return -1;
+}
+
+int aging_files ()
+{
+       char name[MAX_NAMELEN];
+       int sfh;        /* file to be aged */
+       int psfh;
+       int ret;
+       struct stat st;
+       int agefd;
+
+       /* get the sfh and size of the selected file to be aged */
+       sfh = select_obj (&obj_fh, IS_FILE, EXIST, ACTIVE);
+       ret = stat (obj_fh.fh[sfh].path, &st);
+       RFS_ASSERT (ret == 0);
+       ret = truncate(obj_fh.fh[i].path, st.st_size/2);
+       RFS_ASSERT (ret==0);
+
+       psfh = obj_fh.fh[sfh].psfh;
+       strcpy (name, obj_fh.fh[psfh].path);
+       sprintf(name+strlen(name), "/AGE%d", obj_fh.fh_max); 
+       agefd = creat (name, S_IRWXU);
+       //write (agefs, buf, 0);
+
+       add_fh_t (&obj_fh, name, sfh, psfh, size, ftype_flag, EXIST, INACTIVE);
+}
+#endif
diff --git a/TBBT/trace_play/rfs_c_dat.c b/TBBT/trace_play/rfs_c_dat.c
new file mode 100644 (file)
index 0000000..bcd3525
--- /dev/null
@@ -0,0 +1,188 @@
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+dep_tab_t dep_tab[DEP_TAB_SIZE];
+int req_num_with_new_fh = 0;
+int    req_num_with_discard_fh = 0;
+int req_num_with_init_fh =0;
+
+int event_order [EVENT_ORDER_SIZE];
+int event_order_index = 0;
+
+memory_trace_ent_t memory_trace[MAX_MEMORY_TRACE_LINES];
+       
+/* the offset between the replay time and timestamp in the log */
+struct ladtime current;
+#if    0
+//struct ladtime trace_starttime = {1003636801, 39949, 0};
+struct ladtime trace_starttime = {1003723201, 313373, 0};
+#else
+/* timestamp extracted from the used trace. G. Jason Peng */
+//struct ladtime trace_starttime = {1005620400, 499221, 0};
+/* timestamp extracted nfsdump.gzip.pair Ningning for osdi measurement */
+struct ladtime trace_starttime = {1085067131, 107476, 0};
+#endif
+struct ladtime time_offset;
+
+fh_map_t fh_map [FH_MAP_SIZE];
+struct generic_entry * fh_htable[FH_HTABLE_SIZE];
+int fh_i=0;
+int fh_map_debug = 0;
+struct generic_entry * fh_htable [FH_HTABLE_SIZE];
+
+#ifdef notdef
+/* the array is indexed by sfs operation number */
+rfs_op_type rfs_Ops[TOTAL] = {
+{NFSPROC3_NULL,                setbuf_void,            setbuf_void, xdr_void, xdr_void},
+{NFSPROC3_GETATTR,     setarg_GETATTR3,        setbuf_void, xdr_GETATTR3args, xdr_GETATTR3res},
+{NFSPROC3_SETATTR,     setarg_SETATTR3,        setbuf_void, xdr_SETATTR3args, xdr_SETATTR3res},
+{NFSPROC3_INVALID,     setbuf_invalid,         setbuf_invalid, xdr_invalid, xdr_invalid},
+{NFSPROC3_LOOKUP,      setarg_LOOKUP3,         setres_lookup, xdr_LOOKUP3args, xdr_LOOKUP3res},
+{NFSPROC3_READLINK, setarg_READLINK3,  setres_readlink, xdr_READLINK3args, xdr_READLINK3res},
+{NFSPROC3_READ,        setarg_READ3,           setres_read, xdr_READ3args, xdr_READ3res},
+{NFSPROC3_INVALID,     setarg_invalid,         setbuf_invalid, xdr_invalid, xdr_invalid},
+{NFSPROC3_WRITE,       setarg_WRITE3,          setbuf_void, xdr_WRITE3args, xdr_WRITE3res},
+{NFSPROC3_CREATE,      setarg_CREATE3,         setbuf_void, xdr_CREATE3args, xdr_CREATE3res},
+{NFSPROC3_REMOVE,      setarg_REMOVE3,         setbuf_void, xdr_REMOVE3args, xdr_REMOVE3res},
+{NFSPROC3_RENAME,      setarg_RENAME3,         setbuf_void, xdr_RENAME3args, xdr_RENAME3res},
+{NFSPROC3_LINK,        setarg_LINK3,           setbuf_void, xdr_LINK3args, xdr_LINK3res},
+{NFSPROC3_SYMLINK,     setarg_SYMLINK3,        setbuf_void, xdr_SYMLINK3args, xdr_SYMLINK3res},
+{NFSPROC3_MKDIR,       setarg_MKDIR3,          setbuf_void, xdr_MKDIR3args, xdr_MKDIR3res},
+{NFSPROC3_RMDIR,       setarg_RMDIR3,          setbuf_void, xdr_RMDIR3args, xdr_RMDIR3res},
+{NFSPROC3_READDIR,     setarg_READDIR3,        setres_readdir, xdr_READDIR3args, xdr_READDIR3res},
+{NFSPROC3_FSSTAT,      setarg_FSSTAT3,         setbuf_void, xdr_FSSTAT3args, xdr_FSSTAT3res},
+{NFSPROC3_ACCESS,      setarg_ACCESS3,         setbuf_void, xdr_ACCESS3args, xdr_ACCESS3res},
+{NFSPROC3_COMMIT,      setarg_COMMIT3,         setbuf_void, xdr_COMMIT3args, xdr_COMMIT3res},
+{NFSPROC3_FSINFO,      setarg_FSINFO3,         setbuf_void,  xdr_FSINFO3args, xdr_FSINFO3res},
+{NFSPROC3_MKNOD,       setarg_MKNOD3,          setbuf_void, xdr_MKNOD3args, xdr_MKNOD3res},
+{NFSPROC3_PATHCONF, setarg_PATHCONF3,  setbuf_void, xdr_PATHCONF3args, xdr_PATHCONF3res}
+{NFSPROC3_READDIRPLUS, setarg_READDIRPLUS3, setres_readdirplus, xdr_READDIRPLUS3args, xdr_READDIRPLUS3res}};
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+sfs_op_type nfsv3_Ops[] = {
+
+/* name        mix    op    call  no  req  req  req  results */
+/*             pcnt  class  targ call pcnt cnt  targ         */
+
+ { "null",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    11, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     27, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       18, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       9, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     2, Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",      7, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",      5, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",      1, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",       0, Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",    0, Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 9, Read,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+#endif
+
+sfs_op_type *Ops;
+
+int num_out_reqs = 0;
+
+cyclic_index_t dep_tab_index;
+cyclic_index_t dep_window_index;
+cyclic_index_t memory_trace_index;
+int dep_window_max = 0;
+
+/* note that for each dep_tab entry, there is a memory trace line, but
+ * not vise vesa because some memory trace line may not have corresponding
+ * dep_tab entry. According entry TIMESTAMP value, the order is
+ *
+ * memory_trace_tail line < dep_tab_tail entry < dep_window_max entry <
+ * dep_tab_head entry < memory_trace_head entry */
+
+int rfs_debug = 0;
+int per_packet_debug = 0;
+int adjust_play_window_debug = 0;
+int dependency_debug = 0;
+int profile_debug = 0;
+int quiet_flag = 0;
+int stage = FIRST_STAGE;
+int read_data_owe = 0;
+int read_data_total = 0;
+int write_data_owe = 0;
+int write_data_total = 0;
+int read_data_adjust_times = 0;
+int write_data_adjust_times = 0;
+int read_data_owe_GB = 0;
+int write_data_owe_GB = 0;
+int read_data_total_GB = 0;
+int write_data_total_GB = 0;
+
+int failed_create_command_num = 0;
+int failed_other_command_num = 0;
+int skipped_readlink_command_num = 0;
+int skipped_custom_command_num = 0;
+int fh_path_map_err_num = 0;
+int skipped_fsstat_command_num = 0;
+int missing_reply_num = 0;
+int rename_rmdir_noent_reply_num = 0;
+int rmdir_not_empty_reply_num = 0;
+int loose_access_control_reply_num = 0;
+int lookup_err_due_to_rename_num = 0;
+int lookup_err_due_to_parallel_remove_num = 0;
+int lookup_eaccess_enoent_mismatch_num = 0;
+int read_io_err_num = 0;
+int stale_fhandle_err_num = 0;
+int proper_reply_num = 0;
+int run_stage_proper_reply_num = 0;
+int lookup_retry_num = 0;
+int can_not_catch_speed_num = 0;
+int can_not_catch_speed_num_total = 0;
+int poll_timeout_0_num = 0;
+int poll_timeout_pos_num = 0;
+int abnormal_EEXIST_num = 0;
+int abnormal_ENOENT_num = 0;
+
+FILE * profile_fp = 0;
+profile_t total_profile;
+profile_t valid_get_nextop_profile;
+profile_t invalid_get_nextop_profile;
+profile_t valid_poll_and_get_reply_profile;
+profile_t invalid_poll_and_get_reply_profile;
+profile_t execute_next_request_profile;
+profile_t receive_next_reply_profile;
+profile_t decode_reply_profile;
+profile_t check_reply_profile;
+profile_t add_create_object_profile;
+profile_t prepare_argument_profile;
+profile_t biod_clnt_call_profile;
+profile_t check_timeout_profile;
+profile_t adjust_play_window_profile;
+profile_t fgets_profile;
+profile_t read_line_profile;
+profile_t read_trace_profile;
+
+int PLAY_SCALE = 1;
+int skip_sec = 0;
+int trace_timestamp1=0, trace_timestamp2=0;
+
+int disk_io_status = TRACE_BUF_FULL;
+int WARMUP_TIME = 0;   /* other values that has been used: 100 */
+int disk_index = -1;
+
+int TRACE_COMMAND_REPLY_FLAG_POS=36;
+int TRACE_VERSION_POS=37;
+int TRACE_MSGID_POS=39;
+int TRACE_FH_SIZE=64;
diff --git a/TBBT/trace_play/rfs_c_def.h b/TBBT/trace_play/rfs_c_def.h
new file mode 100644 (file)
index 0000000..daeea6c
--- /dev/null
@@ -0,0 +1,357 @@
+#ifndef RFS_H
+#define RFS_H
+#include "sfs_c_def.h"
+#include "profile.h"
+#include "rfs_assert.h"
+
+/* the maximum number of operations depended by one operation */
+/* the dependency include read/write, write/write, all operations with a
+ * one file handle/delete or rename's target if exists, the dependency
+ * does not include the create/all operations with relevant file handle
+ * This dependency is maintained by a flag in file handle mapping table
+ */
+#define MAX_DEP_OPS 10 
+//#define DEP_TAB_SIZE 200000 /* the dependency table size */
+/* Right now we don't wrap around with dep_tab, for each request, there
+ * is one entry in dependency table and one entry in lines buffer.
+ */
+#define REDUCE_MEMORY_TRACE_SIZE
+
+#define EVENT_ORDER_SIZE 1000000
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+//#define DEP_TAB_SIZE  1100000 /* the dependency table size */
+#define DEP_TAB_SIZE    100000 /* the dependency table size */
+//#define DEP_TAB_SIZE  10000 /* the dependency table size */
+#define MAX_MEMORY_TRACE_LINES DEP_TAB_SIZE 
+//#define MAX_TRACE_LINE_LENGTH 768
+#define MAX_TRACE_LINE_LENGTH 300
+#else
+#define MAX_TRACE_LINE_LENGTH 768
+#define DEP_TAB_SIZE   500000 /* the dependency table size */
+#define MAX_MEMORY_TRACE_LINES DEP_TAB_SIZE*2 
+#endif
+
+#define FH_MAP_SIZE 400000
+//#define FH_MAP_SIZE 40000
+#define FH_HTABLE_SIZE FH_MAP_SIZE                                                              
+
+/* trace play policy related defines */
+#define SPEED_UP               // only one of SPEED_UP and     SLOW_DOWN is defined
+//#define SLOW_DOWN
+extern int PLAY_SCALE;
+//#define TIME_PLAY /* play according original timestamp or scaled timestamp together with dependency */
+#define NO_DEPENDENCY_TABLE
+//#define MAX_COMMAND_REPLY_DISTANCE 1000
+#define MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR 1000
+#define MAX_COMMAND_REPLY_DISTANCE 2
+
+#define WORKLOAD_PLAY /* play according dependency and as fast as it can, ignore timestamp */
+
+#ifdef TIME_PLAY
+#define MAX_PLAY_WINDOW 8
+#define MAX_OUTSTANDING_REQ 4  /* too big outstanding window reduces throughput */
+#else
+#define MAX_PLAY_WINDOW 1000
+//#define MAX_PLAY_WINDOW 8
+#define MAX_OUTSTANDING_REQ 8
+//#define MAX_OUTSTANDING_REQ 16
+#endif
+#define UDP    /* currently we only support using UDP, support for TCP will be added later */
+
+/* the flag to indicate the current status of a trace request */
+#define DEP_FLAG_FREE 0                        /* free entry */
+#define DEP_FLAG_INIT 1                        /* initialized */
+#define DEP_FLAG_CANDIDATE 2
+#define DEP_FLAG_WAIT_FHANDLE 3        /* waiting for leading fhandle */
+#define DEP_FLAG_FHANDLE_READY 4
+#define DEP_FLAG_WAIT_DIRECTORY 5
+#define DEP_FLAG_DIRECTORY_READY 6
+#define DEP_FLAG_WAIT_DELETE 7 /* waiting for deleting the object */
+#define DEP_FLAG_SENT 8                        /* Request has been sent out, waiting for replies */
+#define DEP_FLAG_DONE 9                        /* Reply has been received and processed */
+#define BUSY   1
+#define IDLE   0
+
+#define MAX_ARG_RES_SIZE 512
+#define MAX_BUF1_SIZE 65536    /* for readdirplus, 208 each entry, max 128 entries */
+#define MAX_BUF2_SIZE NFS_MAXPATHLEN
+
+extern int TRACE_COMMAND_REPLY_FLAG_POS;
+extern int TRACE_VERSION_POS;
+extern int TRACE_MSGID_POS;
+extern int TRACE_FH_SIZE;
+
+/* Two setbuf_t procedure exists for each NFS operation, one for setting up NFS 
+ * operation argument buffer, another for setting up NFS operation result receiving buffer.
+ *
+ * When setting up argument, the function takes two argument, the first 
+ * argument is index to dep_tab, the second argument is the buffer pointer to 
+ * be setup. Sometimes, there is no extra argument other than index, for example: read
+ * Sometimes, there is one extra argument, e.g the buffer for lookup name.
+ * Sometimes, there are two extra arguments, e..g rename, symlink.
+ *
+ * void (*setbuf_t)(int index, char * arg, char * arg);
+ *
+ * When setting up receiving result buffer, the function takes one arguement,
+ * the buffer pointer.
+ * void (*setbuf_t)(char * res, char * arg);
+ */
+typedef void (*setbuf_t)();
+
+typedef struct {
+       int nfsv3_proc;
+       setbuf_t setarg;
+       setbuf_t setres;
+       xdrproc_t xdr_arg;
+       xdrproc_t xdr_res;
+} rfs_op_type;
+
+#define MAX_TRACE_FH_SIZE 64
+#define TRACE_FH_FILE_SIZE 48
+#define TRACE_FH_DIR_SIZE 40
+#define MAX_PLAY_PATH_SIZE 256
+
+/* flags in fh_map_t */
+#define FH_MAP_FLAG_FREE 0
+#define FH_MAP_FLAG_DISCARD 1
+#define FH_MAP_FLAG_PARTIAL 2
+#define FH_MAP_FLAG_COMPLETE 3
+typedef struct {
+       int flag;
+       int lock;
+       char trace_fh [MAX_TRACE_FH_SIZE+1];
+       char path[MAX_PLAY_PATH_SIZE];
+       nfs_fh3 play_fh;
+} fh_map_t;
+
+typedef struct {
+       int disk_index;
+       int trace_status;
+       char reply_trace_fh[MAX_TRACE_FH_SIZE+1];
+       char line[MAX_TRACE_LINE_LENGTH];
+} memory_trace_ent_t;
+       
+
+typedef struct {
+       int flag;       
+       int disk_index;
+       int memory_index;
+       char * line;
+       char * reply_line;
+       fh_map_t * fh;
+       fh_map_t * fh_2;
+       char * trace_fh;
+       char * trace_fh_2;
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+       char * reply_trace_fh;
+#endif
+       int proc;       /* the prototype independent NFS operation number defined in sfs_c_def.h
+                                * e.g. NULLCALL NFS3PROC_READ etc */
+       struct timeval timestamp;       /* The timestamp of a request in the trace */
+#ifdef NO_DEPENDENCY_TABLE
+       int dep_ops[MAX_DEP_OPS]; /* Other requests need to be processed prior this request */
+                                                                /* dep_tab[i] == -1 means the dependency has been resolved */
+       int init_dep_num;                       /* The number of request being depended initially */
+       int cur_dep_num;                        /* The number of remaining ones which have not been finished */ 
+                                                               /* at initialization time, init_dep_num == cur_dep_num */
+#endif
+       int biod_req_index;     /* Index in to the biod_req array which contains all outstanding requests */
+       struct ladtime start;
+       struct ladtime stop;
+       struct ladtime interval;
+       int skip_sec;
+       int status;
+       int trace_status;
+} dep_tab_t;
+
+typedef struct {
+       char name[32];
+       int head;
+       int tail;
+       int size;
+} cyclic_index_t;
+
+#define CYCLIC_INIT(str,index,SIZE) \
+       {index.head=0; index.tail=0; index.size=SIZE; \
+        RFS_ASSERT(strlen(str)<sizeof(index.name)); \
+        strcpy(index.name, str); }
+
+#define CYCLIC_PRINT(index) \
+       {printf("%s head %d tail %d, size %d\n", index.name, index.head, index.tail, index.size);}
+
+#define CYCLIC_FULL(index) \
+       (((index.head+1)%index.size)==index.tail)
+
+#define CYCLIC_EMPTY(index)    \
+       (index.tail==index.head)
+
+#define CYCLIC_NUM(index) \
+       ((index.head + index.size - index.tail) % index.size)
+
+#define CYCLIC_MOVE_HEAD(index) \
+       { \
+               if (CYCLIC_FULL(index)) { \
+                       CYCLIC_PRINT(index) \
+               } \
+               RFS_ASSERT (!CYCLIC_FULL(index)); \
+               index.head=(index.head+1)%(index.size); \
+       }
+
+#define CYCLIC_MOVE_TAIL(index) \
+       { \
+               RFS_ASSERT (!CYCLIC_EMPTY(index)) \
+               index.tail=(index.tail+1)%(index.size); \
+       }
+
+/*
+#define CYCLIC_MOVE_TAIL_TO(index,dest) \
+       { \
+               int oldnum = CYCLIC_NUM(index); \
+               if (! ((dest>=0) && (dest<index.size) && (dest!=index.head))) { \
+                       CYCLIC_PRINT(index); \
+                       printf("dest %d\n", dest); \
+               } \
+               RFS_ASSERT ((dest>=0) && (dest<index.size) && (dest!=index.head)) \
+               index.tail = dest; \
+               if (CYCLIC_NUM(index) > oldnum) { \
+                       CYCLIC_PRINT(index); \
+                       printf("dest %d old_num %d \n", dest, oldnum); \
+               } \
+               RFS_ASSERT (CYCLIC_NUM(index) <= oldnum); \
+       }
+*/
+
+#define CYCLIC_MINUS(A,B,size) ((A+size-B)%size)
+#define CYCLIC_ADD(A,B,size) ((A+B)%size)
+#define CYCLIC_LESS(index,A,B) \
+(CYCLIC_MINUS(A,index.tail,index.size)<CYCLIC_MINUS(B,index.tail,index.size))
+
+extern struct ladtime current;
+extern struct ladtime trace_starttime;
+extern struct ladtime time_offset;
+
+extern rfs_op_type rfs_Ops[];
+extern sfs_op_type nfsv3_Ops[];
+extern sfs_op_type * Ops;
+extern int num_out_reqs;
+
+extern cyclic_index_t dep_tab_index;
+extern cyclic_index_t dep_window_index;
+extern cyclic_index_t memory_trace_index;
+int dep_window_max; /* the first entry outside of the dependency window */
+/* If ordered by TIMESTAMP,
+ * memory_trace_index.tail <= dep_tab_index.tail < dep_window_max <=
+ * dep_tab_index.head <= memory_trace_index.head
+ */
+
+extern fh_map_t fh_map [FH_MAP_SIZE];
+extern int fh_i;
+extern int fh_map_debug ;
+extern struct generic_entry * fh_htable [FH_HTABLE_SIZE];
+
+extern dep_tab_t dep_tab[DEP_TAB_SIZE];
+extern int req_num_with_new_fh;
+extern int req_num_with_discard_fh;
+extern int req_num_with_init_fh;
+extern memory_trace_ent_t memory_trace[MAX_MEMORY_TRACE_LINES];
+extern int event_order[];
+extern int event_order_index;
+extern struct biod_req * biod_reqp;
+extern int max_biod_reqs;
+extern int rfs_debug;
+extern int per_packet_debug;
+extern int profile_debug;
+extern int adjust_play_window_debug;
+extern int dependency_debug;
+extern int quiet_flag;
+extern int read_data_owe;
+extern int write_data_owe;
+extern int read_data_total;
+extern int write_data_total;
+extern int read_data_adjust_times;
+extern int write_data_adjust_times;
+extern int read_data_owe_GB;
+extern int write_data_owe_GB;
+extern int read_data_total_GB;
+extern int write_data_total_GB;
+
+extern int failed_create_command_num;
+extern int failed_other_command_num;
+extern int skipped_readlink_command_num;
+extern int skipped_custom_command_num;
+extern int fh_path_map_err_num;
+extern int skipped_fsstat_command_num;
+extern int missing_reply_num;
+extern int lookup_noent_reply_num;
+extern int rename_rmdir_noent_reply_num;
+extern int rmdir_not_empty_reply_num;
+extern int loose_access_control_reply_num;
+extern int lookup_err_due_to_rename_num;
+extern int lookup_err_due_to_parallel_remove_num;
+extern int lookup_eaccess_enoent_mismatch_num;
+extern int read_io_err_num;
+extern int stale_fhandle_err_num;
+extern int proper_reply_num;
+extern int run_stage_proper_reply_num;
+extern int lookup_retry_num;
+extern int can_not_catch_speed_num_total;
+extern int can_not_catch_speed_num;
+extern int poll_timeout_0_num;
+extern int poll_timeout_pos_num;
+extern int abnormal_EEXIST_num;
+extern int abnormal_ENOENT_num;
+
+#define FIRST_STAGE 0
+#define READ_DEP_TAB_STAGE 1
+#define TRACE_PLAY_STAGE 2
+extern int stage;
+
+#define IGNORE_SETATTR_CTIME
+//#define TAKE_CARE_SETATTR_GID
+//#define TAKE_CARE_SETATTR_UID
+//#define TAKE_CARE_CREATE_MODE_BY_DAN
+//#define TAKE_CARE_OTHER_FAILED_COMMAND
+//#define TAKE_CARE_CUSTOM_COMMAND
+//#define TAKE_CARE_FSSTAT_COMMAND
+//#define TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+//#define TAKE_CARE_NOEMPTY_RMDIR
+//#define TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+//#define TAKE_CARE_ACCESS_ERROR
+//#define TAKE_CARE_SYMBOLIC_LINK
+#define TOLERANT_READ_IO_ERR
+#define TOLERANT_STALE_FHANDLE_ERR
+#define IO_THREAD
+//#define RECV_THREAD  can not tune up the version with receive thread quickly
+
+extern FILE * profile_fp;
+extern profile_t total_profile;
+extern profile_t valid_get_nextop_profile;
+extern profile_t invalid_get_nextop_profile;
+extern profile_t valid_poll_and_get_reply_profile;
+extern profile_t invalid_poll_and_get_reply_profile;
+extern profile_t execute_next_request_profile;
+extern profile_t receive_next_reply_profile;
+extern profile_t decode_reply_profile;
+extern profile_t check_reply_profile;
+extern profile_t add_create_object_profile;
+extern profile_t prepare_argument_profile;
+extern profile_t biod_clnt_call_profile;
+extern profile_t check_timeout_profile;
+extern profile_t adjust_play_window_profile;
+extern profile_t fgets_profile;
+extern profile_t read_line_profile;
+extern profile_t read_trace_profile;
+
+extern int skip_sec;
+extern int trace_timestamp1, trace_timestamp2;
+//#define SEQUEN_READ
+//#define SEQUEN_READ_NUM 1000
+
+#define TRACE_BUF_FULL 0
+#define TRACE_FILE_END 1
+#define ASYNC_RPC_SEM_KEY 60000
+extern int disk_io_status;
+extern int WARMUP_TIME;
+extern int disk_index; 
+//#define NO_SEM
+#endif
diff --git a/TBBT/trace_play/rpc/auth.h b/TBBT/trace_play/rpc/auth.h
new file mode 100755 (executable)
index 0000000..b184cf5
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * @(#)auth.h     2.1     97/10/23
+ */
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/* @(#)auth.h  2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * auth.h, Authentication interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The data structures are completely opaque to the client.  The client
+ * is required to pass a AUTH * to routines that create rpc
+ * "sessions".
+ */
+
+
+#define MAX_AUTH_BYTES 400
+#define MAXNETNAMELEN  255     /* maximum length of network user's name */
+
+/*
+ * Status returned from authentication check
+ */
+enum auth_stat {
+       AUTH_OK=0,
+       /*
+        * failed at remote end
+        */
+       AUTH_BADCRED=1,                 /* bogus credentials (seal broken) */
+       AUTH_REJECTEDCRED=2,            /* client should begin new session */
+       AUTH_BADVERF=3,                 /* bogus verifier (seal broken) */
+       AUTH_REJECTEDVERF=4,            /* verifier expired or was replayed */
+       AUTH_TOOWEAK=5,                 /* rejected due to security reasons */
+       /*
+        * failed locally
+       */
+       AUTH_INVALIDRESP=6,             /* bogus response verifier */
+       AUTH_FAILED=7                   /* some unknown reason */
+};
+
+union des_block {
+       struct {
+               uint_t high;
+               uint_t low;
+       } key;
+       char c[8];
+};
+typedef union des_block des_block;
+extern bool_t xdr_des_block();
+
+/*
+ * Authentication info.  Opaque to client.
+ */
+struct opaque_auth {
+       enum_t  oa_flavor;              /* flavor of auth */
+       void    *oa_base;               /* address of more auth stuff */
+       uint_t  oa_length;              /* not to exceed MAX_AUTH_BYTES */
+};
+
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+typedef struct {
+       struct  opaque_auth     ah_cred;
+       struct  opaque_auth     ah_verf;
+       union   des_block       ah_key;
+       struct auth_ops {
+               void    (*ah_nextverf)();
+               int     (*ah_marshal)();        /* nextverf & serialize */
+               int     (*ah_validate)();       /* validate varifier */
+               int     (*ah_refresh)();        /* refresh credentials */
+               void    (*ah_destroy)();        /* destroy this structure */
+       } *ah_ops;
+       void * ah_private;
+} AUTH;
+
+
+/*
+ * Authentication ops.
+ * The ops and the auth handle provide the interface to the authenticators.
+ *
+ * AUTH        *auth;
+ * XDR *xdrs;
+ * struct opaque_auth verf;
+ */
+#define AUTH_NEXTVERF(auth)            \
+               ((*((auth)->ah_ops->ah_nextverf))(auth))
+#define auth_nextverf(auth)            \
+               ((*((auth)->ah_ops->ah_nextverf))(auth))
+
+#define AUTH_MARSHALL(auth, xdrs)      \
+               ((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+#define auth_marshall(auth, xdrs)      \
+               ((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+
+#define AUTH_VALIDATE(auth, verfp)     \
+               ((*((auth)->ah_ops->ah_validate))((auth), verfp))
+#define auth_validate(auth, verfp)     \
+               ((*((auth)->ah_ops->ah_validate))((auth), verfp))
+
+#define AUTH_REFRESH(auth)             \
+               ((*((auth)->ah_ops->ah_refresh))(auth))
+#define auth_refresh(auth)             \
+               ((*((auth)->ah_ops->ah_refresh))(auth))
+
+#define AUTH_DESTROY(auth)             \
+               ((*((auth)->ah_ops->ah_destroy))(auth))
+#define auth_destroy(auth)             \
+               ((*((auth)->ah_ops->ah_destroy))(auth))
+
+
+extern struct opaque_auth _null_auth;
+
+
+/*
+ * These are the various implementations of client side authenticators.
+ */
+
+/*
+ * Unix style authentication
+ * AUTH *authunix_create(machname, uid, gid, len, aup_gids)
+ *     char *machname;
+ *     int uid;
+ *     int gid;
+ *     int len;
+ *     int *aup_gids;
+ */
+extern AUTH *authunix_create(char *, uid_t, gid_t, int, gid_t *);
+extern AUTH *authunix_create_default(void);
+extern AUTH *authnone_create();                /* takes no parameters */
+extern AUTH *authdes_create();
+
+#define AUTH_NONE      0               /* no authentication */
+#define        AUTH_NULL       0               /* backward compatibility */
+#define        AUTH_UNIX       1               /* unix style (uid, gids) */
+#define        AUTH_SHORT      2               /* short hand unix style */
+#define AUTH_DES       3               /* des style (encrypted timestamps) */
diff --git a/TBBT/trace_play/rpc/auth_none.c b/TBBT/trace_play/rpc/auth_none.c
new file mode 100755 (executable)
index 0000000..4644ac4
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef lint
+static char sfs_auth_none_c_id[] = "@(#)auth_none.c     2.1     97/10/23";
+#endif
+/* @(#)auth_none.c     2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * auth_none.c
+ * Creates a client authentication handle for passing "null" 
+ * credentials and verifiers to remote systems. 
+ * 
+ * Copyright (C) 1984, Sun Microsystems, Inc. 
+ */
+
+#include <stdlib.h>
+#include "rpc/rpc.h"
+#define MAX_MARSHEL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+static void    authnone_verf(void);
+static void    authnone_destroy(void);
+static bool_t  authnone_marshal(AUTH *, XDR *);
+static bool_t  authnone_validate(void);
+static bool_t  authnone_refresh(void);
+
+static struct auth_ops ops = {
+       authnone_verf,
+       authnone_marshal,
+       authnone_validate,
+       authnone_refresh,
+       authnone_destroy
+};
+
+static struct authnone_private {
+       AUTH    no_client;
+       char    marshalled_client[MAX_MARSHEL_SIZE];
+       uint_t  mcnt;
+} *authnone_private;
+
+AUTH *
+authnone_create(void)
+{
+       register struct authnone_private *ap = authnone_private;
+       XDR xdr_stream;
+       register XDR *xdrs;
+
+       if (ap == 0) {
+               ap = (struct authnone_private *)calloc(1,
+                                       sizeof (struct authnone_private));
+               if (ap == 0)
+                       return (0);
+               authnone_private = ap;
+       }
+       if (!ap->mcnt) {
+               ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
+               ap->no_client.ah_ops = &ops;
+               xdrs = &xdr_stream;
+               xdrmem_create(xdrs, ap->marshalled_client, (uint_t)MAX_MARSHEL_SIZE,
+                   XDR_ENCODE);
+               (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred);
+               (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf);
+               ap->mcnt = XDR_GETPOS(xdrs);
+               XDR_DESTROY(xdrs);
+       }
+       return (&ap->no_client);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_marshal(
+       AUTH *client,
+       XDR *xdrs)
+{
+       register struct authnone_private *ap = authnone_private;
+
+       if (ap == 0)
+               return (0);
+       return ((*xdrs->x_ops->x_putbytes)(xdrs,
+           ap->marshalled_client, ap->mcnt));
+}
+
+static void 
+authnone_verf(void)
+{
+}
+
+static bool_t
+authnone_validate(void)
+{
+
+       return (TRUE);
+}
+
+static bool_t
+authnone_refresh(void)
+{
+
+       return (FALSE);
+}
+
+static void
+authnone_destroy(void)
+{
+}
diff --git a/TBBT/trace_play/rpc/auth_unix.c b/TBBT/trace_play/rpc/auth_unix.c
new file mode 100755 (executable)
index 0000000..06f7033
--- /dev/null
@@ -0,0 +1,345 @@
+#ifndef lint
+static char sfs_auth_unix_c_id[] = "@(#)auth_unix.c     2.1     97/10/23";
+#endif
+/* @(#)auth_unix.c     2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * auth_unix.c, Implements UNIX style authentication parameters. 
+ *  
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The system is very weak.  The client uses no encryption for it's
+ * credentials and only sends null verifiers.  The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "rpc/rpc.h"
+
+extern getmyhostname(char *, int);
+
+/*
+ * Unix authenticator operations vector
+ */
+static void    authunix_nextverf(AUTH *);
+static bool_t  authunix_marshal(AUTH *, XDR *);
+static bool_t  authunix_validate(AUTH *, struct opaque_auth);
+static bool_t  authunix_refresh(AUTH *);
+static void    authunix_destroy(AUTH *);
+
+static struct auth_ops auth_unix_ops = {
+       authunix_nextverf,
+       authunix_marshal,
+       authunix_validate,
+       authunix_refresh,
+       authunix_destroy
+};
+
+/*
+ * This struct is pointed to by the ah_private field of an auth_handle.
+ */
+struct audata {
+       struct opaque_auth      au_origcred;    /* original credentials */
+       struct opaque_auth      au_shcred;      /* short hand cred */
+       uint32_t                au_shfaults;    /* short hand cache faults */
+       char                    au_marshed[MAX_AUTH_BYTES];
+       uint_t                  au_mpos;        /* xdr pos at end of marshed */
+};
+#define        AUTH_PRIVATE(auth)      ((struct audata *)auth->ah_private)
+
+static bool_t marshal_new_auth(AUTH *);
+
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create(
+       char *machname,
+       uid_t uid,
+       gid_t gid,
+       int len,
+       gid_t *aup_gids)
+{
+       struct authunix_parms aup;
+       char mymem[MAX_AUTH_BYTES];
+       struct timeval now;
+       XDR xdrs;
+       register AUTH *auth;
+       register struct audata *au;
+
+       /*
+        * Allocate and set up auth handle
+        */
+       auth = (AUTH *)mem_alloc(sizeof(AUTH));
+#ifndef KERNEL
+       if (auth == NULL) {
+               (void)fprintf(stderr, "authunix_create: out of memory\n");
+               return (NULL);
+       }
+#endif
+       au = (struct audata *)mem_alloc(sizeof(struct audata));
+#ifndef KERNEL
+       if (au == NULL) {
+               (void)fprintf(stderr, "authunix_create: out of memory\n");
+               return (NULL);
+       }
+#endif
+       auth->ah_ops = &auth_unix_ops;
+       auth->ah_private = (void *)au;
+       auth->ah_verf = au->au_shcred = _null_auth;
+       au->au_shfaults = 0;
+
+       /*
+        * fill in param struct from the given params
+        */
+       (void)gettimeofday(&now,  (struct timezone *)0);
+       aup.aup_time = now.tv_sec;
+       aup.aup_machname = machname;
+       aup.aup_uid = uid;
+       aup.aup_gid = gid;
+       aup.aup_len = (uint_t)len;
+       aup.aup_gids = (int *)aup_gids;
+
+       /*
+        * Serialize the parameters into origcred
+        */
+       xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
+       if (! xdr_authunix_parms(&xdrs, &aup)) 
+               abort();
+       au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
+       au->au_origcred.oa_flavor = AUTH_UNIX;
+#ifdef KERNEL
+       au->au_origcred.oa_base = mem_alloc((uint_t) len);
+#else
+       if ((au->au_origcred.oa_base = mem_alloc((uint_t) len)) == NULL) {
+               (void)fprintf(stderr, "authunix_create: out of memory\n");
+               return (NULL);
+       }
+#endif
+       memmove(au->au_origcred.oa_base, mymem, (uint_t)len);
+
+       /*
+        * set auth handle to reflect new cred.
+        */
+       auth->ah_cred = au->au_origcred;
+       marshal_new_auth(auth);
+       return (auth);
+}
+
+/*
+ * Returns an auth handle with parameters determined by doing lots of
+ * syscalls.
+ */
+AUTH *
+authunix_create_default(void)
+{
+       register int len;
+       char machname[MAX_MACHINE_NAME + 1];
+       uid_t uid;
+       gid_t gid;
+       gid_t gids[NGRPS];
+
+       if (getmyhostname(machname, MAX_MACHINE_NAME) == -1)
+               abort();
+       machname[MAX_MACHINE_NAME] = 0;
+       uid = geteuid();
+       gid = getegid();
+       if ((len = getgroups(NGRPS, gids)) < 0)
+               abort();
+       return (authunix_create(machname, uid, gid, len, gids));
+}
+
+/*
+ * authunix operations
+ */
+
+/* ARGSUSED */
+static void
+authunix_nextverf(
+       AUTH *auth)
+{
+       /* no action necessary */
+}
+
+static bool_t
+authunix_marshal(
+       AUTH *auth,
+       XDR *xdrs)
+{
+       register struct audata *au = AUTH_PRIVATE(auth);
+
+       return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
+}
+
+static bool_t
+authunix_validate(
+       AUTH *auth,
+       struct opaque_auth verf)
+{
+       register struct audata *au;
+       XDR xdrs;
+
+       if (verf.oa_flavor == AUTH_SHORT) {
+               au = AUTH_PRIVATE(auth);
+               xdrmem_create(&xdrs, verf.oa_base, verf.oa_length, XDR_DECODE);
+
+               if (au->au_shcred.oa_base != NULL) {
+                       mem_free(au->au_shcred.oa_base,
+                           au->au_shcred.oa_length);
+                       au->au_shcred.oa_base = NULL;
+               }
+               if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
+                       auth->ah_cred = au->au_shcred;
+               } else {
+                       xdrs.x_op = XDR_FREE;
+                       (void)xdr_opaque_auth(&xdrs, &au->au_shcred);
+                       au->au_shcred.oa_base = NULL;
+                       auth->ah_cred = au->au_origcred;
+               }
+               marshal_new_auth(auth);
+       }
+       return (TRUE);
+}
+
+static bool_t
+authunix_refresh(
+       AUTH *auth)
+{
+       register struct audata *au = AUTH_PRIVATE(auth);
+       struct authunix_parms aup;
+       struct timeval now;
+       XDR xdrs;
+       register int stat;
+
+       if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
+               /* there is no hope.  Punt */
+               return (FALSE);
+       }
+       au->au_shfaults ++;
+
+       /* first deserialize the creds back into a struct authunix_parms */
+       aup.aup_machname = NULL;
+       aup.aup_gids = (int *)NULL;
+       xdrmem_create(&xdrs, au->au_origcred.oa_base,
+           au->au_origcred.oa_length, XDR_DECODE);
+       stat = xdr_authunix_parms(&xdrs, &aup);
+       if (! stat) 
+               goto done;
+
+       /* update the time and serialize in place */
+       (void)gettimeofday(&now, (struct timezone *)0);
+       aup.aup_time = now.tv_sec;
+       xdrs.x_op = XDR_ENCODE;
+       XDR_SETPOS(&xdrs, 0);
+       stat = xdr_authunix_parms(&xdrs, &aup);
+       if (! stat)
+               goto done;
+       auth->ah_cred = au->au_origcred;
+       marshal_new_auth(auth);
+done:
+       /* free the struct authunix_parms created by deserializing */
+       xdrs.x_op = XDR_FREE;
+       (void)xdr_authunix_parms(&xdrs, &aup);
+       XDR_DESTROY(&xdrs);
+       return (stat);
+}
+
+static void
+authunix_destroy(
+       AUTH *auth)
+{
+       register struct audata *au = AUTH_PRIVATE(auth);
+
+       mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
+
+       if (au->au_shcred.oa_base != NULL)
+               mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
+
+       mem_free(auth->ah_private, sizeof(struct audata));
+
+       if (auth->ah_verf.oa_base != NULL)
+               mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
+
+       mem_free((void *)auth, sizeof(AUTH));
+}
+
+/*
+ * Marshals (pre-serializes) an auth struct.
+ * sets private data, au_marshed and au_mpos
+ */
+static bool_t
+marshal_new_auth(
+       AUTH *auth)
+{
+       XDR             xdr_stream;
+       register XDR    *xdrs = &xdr_stream;
+       register struct audata *au = AUTH_PRIVATE(auth);
+
+       xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
+       if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
+           (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
+               perror("auth_none.c - Fatal marshalling problem");
+       } else {
+               au->au_mpos = XDR_GETPOS(xdrs);
+       }
+       XDR_DESTROY(xdrs);
+       return (TRUE);
+}
diff --git a/TBBT/trace_play/rpc/auth_unix.h b/TBBT/trace_play/rpc/auth_unix.h
new file mode 100755 (executable)
index 0000000..24147e0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * @(#)auth_unix.h     2.1     97/10/23
+ */
+
+/* @(#)auth_unix.h     2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)auth_unix.h 1.5 86/07/16 SMI      */
+
+/*
+ * auth_unix.h, Protocol for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+
+/*
+ * The system is very weak.  The client uses no encryption for  it
+ * credentials and only sends null verifiers.  The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ */
+
+/* The machine name is part of a credential; it may not exceed 255 bytes */
+#define MAX_MACHINE_NAME 255
+
+/* gids compose part of a credential; there may not be more than 16 of them */
+#define NGRPS 16
+
+/*
+ * Unix style credentials.
+ */
+struct authunix_parms {
+       uint32_t aup_time;
+       char    *aup_machname;
+       int      aup_uid;
+       int      aup_gid;
+       uint_t   aup_len;
+       int     *aup_gids;
+};
+
+extern bool_t xdr_authunix_parms();
+
+/* 
+ * If a response verifier has flavor AUTH_SHORT, 
+ * then the body of the response verifier encapsulates the following structure;
+ * again it is serialized in the obvious fashion.
+ */
+struct short_hand_verf {
+       struct opaque_auth new_cred;
+};
diff --git a/TBBT/trace_play/rpc/authunix_prot.c b/TBBT/trace_play/rpc/authunix_prot.c
new file mode 100755 (executable)
index 0000000..bc18e7b
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef lint
+static char sfs_authunix_prot_c_id[] = "@(#)authunix_prot.c     2.1     97/10/23";
+#endif
+/* @(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/auth.h"
+#include "rpc/auth_unix.h"
+
+/*
+ * XDR for unix authentication parameters.
+ */
+bool_t
+xdr_authunix_parms(
+       XDR *xdrs,
+       struct authunix_parms *p)
+{
+
+       if (xdr_uint32_t(xdrs, &(p->aup_time))
+           && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME)
+           && xdr_int(xdrs, &(p->aup_uid))
+           && xdr_int(xdrs, &(p->aup_gid))
+           && xdr_array(xdrs, (void **)&(p->aup_gids),
+                   &(p->aup_len), NGRPS, sizeof(int), xdr_int) ) {
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
diff --git a/TBBT/trace_play/rpc/bindresvport.c b/TBBT/trace_play/rpc/bindresvport.c
new file mode 100755 (executable)
index 0000000..32927fe
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef lint
+static char sfs_bindresvport_id[] = "@(#)bindresvport.c     2.1     97/10/23";
+#endif
+/* 2.2 88/07/29 4.0 RPCSRC 1.8 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "rpc/rpc.h"
+#include <sys/types.h>
+#include "rpc/osdep.h"
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(
+       int sd,
+       struct sockaddr_in *sin)
+{
+       int res;
+       static int16_t port;
+       struct sockaddr_in myaddr;
+       int i;
+
+#define STARTPORT 600
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS (ENDPORT - STARTPORT + 1)
+
+       if (sin == (struct sockaddr_in *)0) {
+               sin = &myaddr;
+               memset(sin, '\0', sizeof (struct sockaddr_in));
+               sin->sin_family = AF_INET;
+       } else if (sin->sin_family != AF_INET) {
+               errno = EPFNOSUPPORT;
+               return (-1);
+       }
+       if (port == 0) {
+               port = (getpid() % NPORTS) + STARTPORT;
+       }
+       res = -1;
+       errno = EADDRINUSE;
+       for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) {
+               sin->sin_port = htons(port++);
+               if (port > ENDPORT) {
+                       port = STARTPORT;
+               }
+               res = bind(sd, (struct sockaddr *)sin, sizeof(struct sockaddr_in));
+       }
+       return (res);
+}
diff --git a/TBBT/trace_play/rpc/clnt.h b/TBBT/trace_play/rpc/clnt.h
new file mode 100755 (executable)
index 0000000..3288d5b
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * @(#)clnt.h     2.1     97/10/23
+ */
+
+/* @(#)clnt.h  2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * clnt.h - Client side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+
+#ifndef _CLNT_
+#define _CLNT_
+
+/*
+ * Rpc calls return an enum clnt_stat.  This should be looked at more,
+ * since each implementation is required to live with this (implementation
+ * independent) list of errors.
+ */
+enum clnt_stat {
+       RPC_SUCCESS=0,                  /* call succeeded */
+       /*
+        * local errors
+        */
+       RPC_CANTENCODEARGS=1,           /* can't encode arguments */
+       RPC_CANTDECODERES=2,            /* can't decode results */
+       RPC_CANTSEND=3,                 /* failure in sending call */
+       RPC_CANTRECV=4,                 /* failure in receiving result */
+       RPC_TIMEDOUT=5,                 /* call timed out */
+       /*
+        * remote errors
+        */
+       RPC_VERSMISMATCH=6,             /* rpc versions not compatible */
+       RPC_AUTHERROR=7,                /* authentication error */
+       RPC_PROGUNAVAIL=8,              /* program not available */
+       RPC_PROGVERSMISMATCH=9,         /* program version mismatched */
+       RPC_PROCUNAVAIL=10,             /* procedure unavailable */
+       RPC_CANTDECODEARGS=11,          /* decode arguments error */
+       RPC_SYSTEMERROR=12,             /* generic "other problem" */
+
+       /*
+        * callrpc & clnt_create errors
+        */
+       RPC_UNKNOWNHOST=13,             /* unknown host name */
+       RPC_UNKNOWNPROTO=17,            /* unkown protocol */
+
+       /*
+        * _ create errors
+        */
+       RPC_PMAPFAILURE=14,             /* the pmapper failed in its call */
+       RPC_PROGNOTREGISTERED=15,       /* remote program is not registered */
+       /*
+        * unspecified error
+        */
+       RPC_FAILED=16
+};
+
+
+/*
+ * Error info.
+ */
+struct rpc_err {
+       enum clnt_stat re_status;
+       union {
+               int RE_errno;           /* realated system error */
+               enum auth_stat RE_why;  /* why the auth error occurred */
+               struct {
+                       uint32_t low;   /* lowest verion supported */
+                       uint32_t high;  /* highest verion supported */
+               } RE_vers;
+               struct {                /* maybe meaningful if RPC_FAILED */
+                       int32_t s1;
+                       int32_t s2;
+               } RE_lb;                /* life boot & debugging only */
+       } ru;
+#define        re_errno        ru.RE_errno
+#define        re_why          ru.RE_why
+#define        re_vers         ru.RE_vers
+#define        re_lb           ru.RE_lb
+};
+
+
+/*
+ * Client rpc handle.
+ * Created by individual implementations, see e.g. rpc_udp.c.
+ * Client is responsible for initializing auth, see e.g. auth_none.c.
+ */
+typedef struct {
+       AUTH    *cl_auth;                       /* authenticator */
+       struct clnt_ops *cl_ops;
+       void    *cl_private;                    /* private stuff */
+} CLIENT;
+
+struct clnt_ops {
+       enum clnt_stat  (*cl_call)(CLIENT *, uint32_t, xdrproc_t, void *, xdrproc_t, void *, struct timeval);
+       void            (*cl_abort)(CLIENT *);
+       void            (*cl_geterr)(CLIENT *, struct rpc_err *);
+       bool_t          (*cl_freeres)(CLIENT *, xdrproc_t, void *);
+       void            (*cl_destroy)(CLIENT *);
+       bool_t          (*cl_control)(CLIENT *, uint_t, void *);
+       bool_t          (*cl_getreply)(CLIENT *, xdrproc_t, void *, int,
+                               uint32_t *, uint32_t *, struct timeval *);
+       int             (*cl_poll)(CLIENT *, uint32_t);
+};
+
+/*
+ * client side rpc interface ops
+ *
+ * Parameter types are:
+ *
+ */
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout)
+ *     CLIENT *rh;
+ *     uint32_t proc;
+ *     xdrproc_t xargs;
+ *     void * argsp;
+ *     xdrproc_t xres;
+ *     void * resp;
+ *     struct timeval timeout;
+ */
+#define        CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs)     \
+       ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+#define        clnt_call(rh, proc, xargs, argsp, xres, resp, secs)     \
+       ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+
+/*
+ * void
+ * CLNT_ABORT(rh);
+ *     CLIENT *rh;
+ */
+#define        CLNT_ABORT(rh)  ((*(rh)->cl_ops->cl_abort)(rh))
+#define        clnt_abort(rh)  ((*(rh)->cl_ops->cl_abort)(rh))
+
+/*
+ * struct rpc_err
+ * CLNT_GETERR(rh);
+ *     CLIENT *rh;
+ */
+#define        CLNT_GETERR(rh,errp)    ((*(rh)->cl_ops->cl_geterr)(rh, errp))
+#define        clnt_geterr(rh,errp)    ((*(rh)->cl_ops->cl_geterr)(rh, errp))
+
+
+/*
+ * bool_t
+ * CLNT_FREERES(rh, xres, resp);
+ *     CLIENT *rh;
+ *     xdrproc_t xres;
+ *     void * resp;
+ */
+#define        CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+#define        clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+
+/*
+ * bool_t
+ * CLNT_CONTROL(cl, request, info)
+ *      CLIENT *cl;
+ *      uint_t request;
+ *      void *info;
+ */
+#define        CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+#define        clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+
+/*
+ * control operations that apply to both udp and tcp transports
+ */
+#define CLSET_TIMEOUT       1   /* set timeout (timeval) */
+#define CLGET_TIMEOUT       2   /* get timeout (timeval) */
+#define CLGET_SERVER_ADDR   3   /* get server's address (sockaddr) */
+/*
+ * udp only control operations
+ */
+#define CLSET_RETRY_TIMEOUT 4   /* set retry timeout (timeval) */
+#define CLGET_RETRY_TIMEOUT 5   /* get retry timeout (timeval) */
+
+/*
+ * void
+ * CLNT_DESTROY(rh);
+ *     CLIENT *rh;
+ */
+#define        CLNT_DESTROY(rh)        ((*(rh)->cl_ops->cl_destroy)(rh))
+#define        clnt_destroy(rh)        ((*(rh)->cl_ops->cl_destroy)(rh))
+
+/*
+ * bool_t
+ * CLNT_GETREPLY(rh,xres,xresp,xid,tv)
+ *     CLIENT *rh;
+ *     xdrproc_t xres;
+ *     void * resp;
+ *     int cnt;
+ *     uint32_t *xids;
+ *     uint32_t *xid;
+ *     struct timeval *tv;
+ */
+#define        CLNT_GETREPLY(rh,xres,xresp,cnt,xids,xid,tv) ((*(rh)->cl_ops->cl_getreply)(rh,xres,xresp,cnt,xids,xid,tv))
+#define        clnt_getreply(rh,xres,xresp,cnt,xids,xid,tv) ((*(rh)->cl_ops->cl_getreply)(rh,xres,xresp,cnt,xids,xid,tv))
+
+/*
+ * bool_t
+ * CLNT_POLL(rh,xusec)
+ *     CLIENT *rh;
+ *     uint32_t xusec;
+ */
+#define        CLNT_POLL(rh,xid) ((*(rh)->cl_ops->cl_poll)(rh,xid))
+#define        clnt_poll(rh,xid) ((*(rh)->cl_ops->cl_poll)(rh,xid))
+
+/*
+ * RPCTEST is a test program which is accessable on every rpc
+ * transport/port.  It is used for testing, performance evaluation,
+ * and network administration.
+ */
+
+#define RPCTEST_PROGRAM                ((uint32_t)1)
+#define RPCTEST_VERSION                ((uint32_t)1)
+#define RPCTEST_NULL_PROC      ((uint32_t)2)
+#define RPCTEST_NULL_BATCH_PROC        ((uint32_t)3)
+
+/*
+ * By convention, procedure 0 takes null arguments and returns them
+ */
+
+#define NULLPROC ((uint32_t)0)
+
+/*
+ * Below are the client handle creation routines for the various
+ * implementations of client side rpc.  They can return NULL if a 
+ * creation failure occurs.
+ */
+
+/*
+ * Memory based rpc (for speed check and testing)
+ * CLIENT *
+ * clntraw_create(prog, vers)
+ *     uint32_t prog;
+ *     uint32_t vers;
+ */
+extern CLIENT *clntraw_create(uint32_t, uint32_t);
+
+/*
+ * Generic client creation routine. Supported protocols are "udp" and "tcp"
+ */
+extern CLIENT *clnt_create(char *, uint32_t, uint32_t, char *);
+
+
+/*
+ * TCP based rpc
+ * CLIENT *
+ * sfs_ctcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ *     struct sockaddr_in *raddr;
+ *     uint32_t prog;
+ *     uint32_t version;
+ *     register int *sockp;
+ *     uint_t sendsz;
+ *     uint_t recvsz;
+ */
+extern CLIENT *sfs_ctcp_create(struct sockaddr_in *, uint32_t, uint32_t,
+                                       int *, uint_t, uint_t);
+extern CLIENT *clnttcp_create(struct sockaddr_in *, uint32_t, uint32_t,
+                                       int *, uint_t, uint_t);
+
+/*
+ * UDP based rpc.
+ * CLIENT *
+ * sfs_cudp_create(raddr, program, version, wait, sockp)
+ *     struct sockaddr_in *raddr;
+ *     uint32_t program;
+ *     uint32_t version;
+ *     struct timeval wait;
+ *     int *sockp;
+ *
+ * Same as above, but you specify max packet sizes.
+ * CLIENT *
+ * sfs_cudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
+ *     struct sockaddr_in *raddr;
+ *     uint32_t program;
+ *     uint32_t version;
+ *     struct timeval wait;
+ *     int *sockp;
+ *     uint_t sendsz;
+ *     uint_t recvsz;
+ */
+extern CLIENT *clntudp_create(struct sockaddr_in *, uint32_t, uint32_t,
+                                       struct timeval, int *);
+extern CLIENT *clntudp_bufcreate(struct sockaddr_in *, uint32_t, uint32_t,
+                                       struct timeval, int *, uint_t, uint_t);
+extern CLIENT *sfs_cudp_create(struct sockaddr_in *, uint32_t, uint32_t,
+                                       struct timeval, int *);
+extern CLIENT *sfs_cudp_bufcreate(struct sockaddr_in *, uint32_t, uint32_t,
+                                       struct timeval, int *, uint_t, uint_t);
+
+/*
+ * Print why creation failed
+ */
+extern void clnt_pcreateerror(char *);
+extern char *clnt_spcreateerror(char *);
+
+/*
+ * Like clnt_perror(), but is more verbose in its output
+ */ 
+extern void clnt_perrno(enum clnt_stat);
+
+/*
+ * Print an English error message, given the client error code
+ */
+extern void clnt_perror(CLIENT *, char *);
+extern char *clnt_sperror(CLIENT *, char *);
+
+/* 
+ * If a creation fails, the following allows the user to figure out why.
+ */
+struct rpc_createerr {
+       enum clnt_stat cf_stat;
+       struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */
+};
+
+extern struct rpc_createerr rpc_createerr;
+
+/*
+ * Copy error message to buffer.
+ */
+extern char *clnt_sperrno(enum clnt_stat);
+
+extern int callrpc(char *, int, int, int, xdrproc_t, char *, xdrproc_t, char *);
+
+extern int bindresvport(int sd, struct sockaddr_in *sin);
+
+#define UDPMSGSIZE     (63 * 1024) /* rpc imposed limit on udp msg size */
+#define RPCSMALLMSGSIZE        400         /* a more reasonable packet size */
+
+#if !defined(RPC_ANYSOCK)
+#define RPC_ANYSOCK     -1
+#endif
+
+#endif /*!_CLNT_*/
diff --git a/TBBT/trace_play/rpc/clnt_generic.c b/TBBT/trace_play/rpc/clnt_generic.c
new file mode 100755 (executable)
index 0000000..16538ef
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef lint
+static char sfs_clnt_generic_id[] = "@(#)clnt_generic.c     2.1     97/10/23";
+#endif
+
+/* @(#)clnt_generic.c  2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
+#endif
+/*
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <errno.h>
+#include <netdb.h>
+
+/*
+ * Generic client creation: takes (hostname, program-number, protocol) and
+ * returns client handle. Default options are set, which the user can 
+ * change using the rpc equivalent of ioctl()'s.
+ */
+CLIENT *
+clnt_create(char *hostname,
+       uint32_t prog,
+       uint32_t vers,
+       char *proto)
+{
+       struct hostent *h;
+       struct protoent *p;
+       struct sockaddr_in sin;
+       int sock;
+       struct timeval tv;
+       CLIENT *client;
+
+       h = gethostbyname(hostname);
+       if (h == NULL) {
+               rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+               return (NULL);
+       }
+       if (h->h_addrtype != AF_INET) {
+               /*
+                * Only support INET for now
+                */
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = EAFNOSUPPORT; 
+               return (NULL);
+       }
+       sin.sin_family = h->h_addrtype;
+       sin.sin_port = 0;
+       memset(sin.sin_zero, '\0', sizeof(sin.sin_zero));
+       memmove((char*)&sin.sin_addr, h->h_addr, h->h_length);
+       p = getprotobyname(proto);
+       if (p == NULL) {
+               rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+               rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; 
+               return (NULL);
+       }
+       sock = RPC_ANYSOCK;
+       switch (p->p_proto) {
+       case IPPROTO_UDP:
+               tv.tv_sec = 5;
+               tv.tv_usec = 0;
+               client = sfs_cudp_create(&sin, prog, vers, tv, &sock);
+               if (client == NULL) {
+                       return (NULL);
+               }
+               tv.tv_sec = 25;
+               clnt_control(client, CLSET_TIMEOUT, &tv);
+               break;
+       case IPPROTO_TCP:
+               client = sfs_ctcp_create(&sin, prog, vers, &sock, 0, 0);
+               if (client == NULL) {
+                       return (NULL);
+               }
+               tv.tv_sec = 25;
+               tv.tv_usec = 0;
+               clnt_control(client, CLSET_TIMEOUT, &tv);
+               break;
+       default:
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; 
+               return (NULL);
+       }
+       return (client);
+}
diff --git a/TBBT/trace_play/rpc/clnt_perror.c b/TBBT/trace_play/rpc/clnt_perror.c
new file mode 100755 (executable)
index 0000000..71d1502
--- /dev/null
@@ -0,0 +1,316 @@
+#ifndef lint
+static char sfs_clnt_perror_c_id[] = "@(#)clnt_perror.c     2.1     97/10/23";
+#endif
+/* @(#)clnt_perror.c   2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_perror.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rpc/rpc.h"
+
+static char *auth_errmsg(enum auth_stat);
+
+static char *
+_buf()
+{
+       static char *buf = NULL;
+       if (buf == NULL)
+               buf = (char *)malloc(256);
+       return (buf);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror(
+       CLIENT *rpch,
+       char *s)
+{
+       struct rpc_err e;
+       char *err;
+       char *str = _buf();
+       char *strstart = str;
+
+       if (str == 0)
+               return (0);
+       CLNT_GETERR(rpch, &e);
+
+       (void) sprintf(str, "%s: ", s);  
+       str += strlen(str);
+
+       (void) strcpy(str, clnt_sperrno(e.re_status));  
+       str += strlen(str);
+
+       switch (e.re_status) {
+       case RPC_SUCCESS:
+       case RPC_CANTENCODEARGS:
+       case RPC_CANTDECODERES:
+       case RPC_TIMEDOUT:     
+       case RPC_PROGUNAVAIL:
+       case RPC_PROCUNAVAIL:
+       case RPC_CANTDECODEARGS:
+       case RPC_SYSTEMERROR:
+       case RPC_UNKNOWNHOST:
+       case RPC_UNKNOWNPROTO:
+       case RPC_PMAPFAILURE:
+       case RPC_PROGNOTREGISTERED:
+       case RPC_FAILED:
+               break;
+
+       case RPC_CANTSEND:
+       case RPC_CANTRECV:
+               (void) sprintf(str, "; errno = %s",
+                   strerror(e.re_errno)); 
+               str += strlen(str);
+               break;
+
+       case RPC_VERSMISMATCH:
+               (void) sprintf(str,
+                       "; low version = %lu, high version = %lu", 
+                       e.re_vers.low, e.re_vers.high);
+               str += strlen(str);
+               break;
+
+       case RPC_AUTHERROR:
+               err = auth_errmsg(e.re_why);
+               (void) sprintf(str,"; why = ");
+               str += strlen(str);
+               if (err != NULL) {
+                       (void) sprintf(str, "%s",err);
+               } else {
+                       (void) sprintf(str,
+                               "(unknown authentication error - %d)",
+                               (int) e.re_why);
+               }
+               str += strlen(str);
+               break;
+
+       case RPC_PROGVERSMISMATCH:
+               (void) sprintf(str, 
+                       "; low version = %lu, high version = %lu", 
+                       e.re_vers.low, e.re_vers.high);
+               str += strlen(str);
+               break;
+
+       default:        /* unknown */
+               (void) sprintf(str, 
+                       "; s1 = %lu, s2 = %lu", 
+                       e.re_lb.s1, e.re_lb.s2);
+               str += strlen(str);
+               break;
+       }
+       (void) sprintf(str, "\n");
+       return(strstart) ;
+}
+
+void
+clnt_perror(
+       CLIENT *rpch,
+       char *s)
+{
+       (void) fprintf(stderr,"%s",clnt_sperror(rpch,s));
+}
+
+
+struct rpc_errtab {
+       enum clnt_stat status;
+       char *message;
+};
+
+static struct rpc_errtab  rpc_errlist[] = {
+       { RPC_SUCCESS, 
+               "RPC: Success" }, 
+       { RPC_CANTENCODEARGS, 
+               "RPC: Can't encode arguments" },
+       { RPC_CANTDECODERES, 
+               "RPC: Can't decode result" },
+       { RPC_CANTSEND, 
+               "RPC: Unable to send" },
+       { RPC_CANTRECV, 
+               "RPC: Unable to receive" },
+       { RPC_TIMEDOUT, 
+               "RPC: Timed out" },
+       { RPC_VERSMISMATCH, 
+               "RPC: Incompatible versions of RPC" },
+       { RPC_AUTHERROR, 
+               "RPC: Authentication error" },
+       { RPC_PROGUNAVAIL, 
+               "RPC: Program unavailable" },
+       { RPC_PROGVERSMISMATCH, 
+               "RPC: Program/version mismatch" },
+       { RPC_PROCUNAVAIL, 
+               "RPC: Procedure unavailable" },
+       { RPC_CANTDECODEARGS, 
+               "RPC: Server can't decode arguments" },
+       { RPC_SYSTEMERROR, 
+               "RPC: Remote system error" },
+       { RPC_UNKNOWNHOST, 
+               "RPC: Unknown host" },
+       { RPC_UNKNOWNPROTO,
+               "RPC: Unknown protocol" },
+       { RPC_PMAPFAILURE, 
+               "RPC: Port mapper failure" },
+       { RPC_PROGNOTREGISTERED, 
+               "RPC: Program not registered"},
+       { RPC_FAILED, 
+               "RPC: Failed (unspecified error)"}
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(
+       enum clnt_stat stat)
+{
+       int i;
+
+       for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) {
+               if (rpc_errlist[i].status == stat) {
+                       return (rpc_errlist[i].message);
+               }
+       }
+       return ("RPC: (unknown error code)");
+}
+
+void
+clnt_perrno(
+       enum clnt_stat num)
+{
+       (void) fprintf(stderr,"%s",clnt_sperrno(num));
+}
+
+
+char *
+clnt_spcreateerror(char *s)
+{
+       char *sp;
+       char *str = _buf();
+
+       if (str == 0)
+               return(0);
+       (void) sprintf(str, "%s: ", s);
+       (void) strcat(str, clnt_sperrno(rpc_createerr.cf_stat));
+       switch (rpc_createerr.cf_stat) {
+       case RPC_PMAPFAILURE:
+               (void) strcat(str, " - ");
+               (void) strcat(str,
+                   clnt_sperrno(rpc_createerr.cf_error.re_status));
+               break;
+
+       case RPC_SYSTEMERROR:
+               sp = strerror(rpc_createerr.cf_error.re_errno);
+               (void) strcat(str, " - ");
+               if (rpc_createerr.cf_error.re_errno > 0
+                   && sp != NULL)
+                       (void) strcat(str, sp);
+               else
+                       (void) sprintf(&str[strlen(str)], "Error %d",
+                           rpc_createerr.cf_error.re_errno);
+               break;
+       }
+       (void) strcat(str, "\n");
+       return (str);
+}
+
+void
+clnt_pcreateerror(char *s)
+{
+       (void) fprintf(stderr, "%s", clnt_spcreateerror(s));
+}
+
+struct auth_errtab {
+       enum auth_stat status;  
+       char *message;
+};
+
+static struct auth_errtab auth_errlist[] = {
+       { AUTH_OK,
+               "Authentication OK" },
+       { AUTH_BADCRED,
+               "Invalid client credential" },
+       { AUTH_REJECTEDCRED,
+               "Server rejected credential" },
+       { AUTH_BADVERF,
+               "Invalid client verifier" },
+       { AUTH_REJECTEDVERF,
+               "Server rejected verifier" },
+       { AUTH_TOOWEAK,
+               "Client credential too weak" },
+       { AUTH_INVALIDRESP,
+               "Invalid server verifier" },
+       { AUTH_FAILED,
+               "Failed (unspecified error)" },
+};
+
+static char *
+auth_errmsg(
+       enum auth_stat stat)
+{
+       int i;
+
+       for (i = 0; i < sizeof(auth_errlist)/sizeof(struct auth_errtab); i++) {
+               if (auth_errlist[i].status == stat) {
+                       return(auth_errlist[i].message);
+               }
+       }
+       return(NULL);
+}
diff --git a/TBBT/trace_play/rpc/clnt_simple.c b/TBBT/trace_play/rpc/clnt_simple.c
new file mode 100755 (executable)
index 0000000..ab5ae9a
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef lint
+static char sfs_clnt_simple_id[] = "@(#)clnt_simple.c     2.1     97/10/23";
+#endif
+/* @(#)clnt_simple.c   2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/* 
+ * clnt_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+#include <string.h>
+
+static struct callrpc_private {
+       CLIENT  *client;
+       int     socket;
+       int     oldprognum, oldversnum, valid;
+       char    *oldhost;
+} *callrpc_private;
+
+callrpc(
+       char *host,
+       int prognum,
+       int versnum,
+       int procnum,
+       xdrproc_t inproc,
+       char *in,
+       xdrproc_t outproc,
+       char *out)
+{
+       register struct callrpc_private *crp = callrpc_private;
+       struct sockaddr_in server_addr;
+       enum clnt_stat clnt_stat;
+       struct hostent *hp;
+       struct timeval timeout, tottimeout;
+
+       if (crp == 0) {
+               crp = (struct callrpc_private *)calloc(1,
+                                       sizeof (struct callrpc_private));
+               if (crp == 0)
+                       return (0);
+               callrpc_private = crp;
+       }
+       if (crp->oldhost == NULL) {
+               crp->oldhost = malloc(256);
+               crp->oldhost[0] = 0;
+               crp->socket = RPC_ANYSOCK;
+       }
+       if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum
+               && strcmp(crp->oldhost, host) == 0) {
+               /* reuse old client */          
+       } else {
+               crp->valid = 0;
+               (void)close(crp->socket);
+               crp->socket = RPC_ANYSOCK;
+               if (crp->client) {
+                       clnt_destroy(crp->client);
+                       crp->client = NULL;
+               }
+               if ((hp = gethostbyname(host)) == NULL)
+                       return ((int) RPC_UNKNOWNHOST);
+               timeout.tv_usec = 0;
+               timeout.tv_sec = 5;
+               memmove((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length);
+               server_addr.sin_family = AF_INET;
+               server_addr.sin_port =  0;
+               if ((crp->client = clntudp_create(&server_addr, (uint32_t)prognum,
+                   (uint32_t)versnum, timeout, &crp->socket)) == NULL)
+                       return ((int) rpc_createerr.cf_stat);
+               crp->valid = 1;
+               crp->oldprognum = prognum;
+               crp->oldversnum = versnum;
+               (void) strcpy(crp->oldhost, host);
+       }
+       tottimeout.tv_sec = 25;
+       tottimeout.tv_usec = 0;
+       clnt_stat = clnt_call(crp->client, procnum, inproc, in,
+           outproc, out, tottimeout);
+       /* 
+        * if call failed, empty cache
+        */
+       if (clnt_stat != RPC_SUCCESS)
+               crp->valid = 0;
+       return ((int) clnt_stat);
+}
diff --git a/TBBT/trace_play/rpc/clnt_tcp.c b/TBBT/trace_play/rpc/clnt_tcp.c
new file mode 100755 (executable)
index 0000000..4054f01
--- /dev/null
@@ -0,0 +1,522 @@
+#ifndef lint
+static char sfs_clnt_tcp_c_id[] = "@(#)clnt_tcp.c     2.1     97/10/23";
+#endif
+/* @(#)clnt_tcp.c      2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+#endif
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer.  The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message.  Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+#include <errno.h>
+#include "rpc/pmap_clnt.h"
+
+#define MCALL_MSG_SIZE 24
+
+struct ct_data {
+       int             ct_sock;
+       bool_t          ct_closeit;
+       struct timeval  ct_wait;
+       bool_t          ct_waitset;       /* wait set by clnt_control? */
+       struct sockaddr_in ct_addr; 
+       struct rpc_err  ct_error;
+       char            ct_mcall[MCALL_MSG_SIZE];       /* marshalled callmsg */
+       uint_t          ct_mpos;                        /* pos after marshal */
+       XDR             ct_xdrs;
+};
+
+static int     readtcp(struct ct_data *, char *, int);
+static int     writetcp(struct ct_data *, char *, int);
+
+static enum clnt_stat  clnttcp_call(CLIENT *, uint32_t, xdrproc_t, void *,
+                                       xdrproc_t, void *, struct timeval);
+static void            clnttcp_abort(CLIENT *);
+static void            clnttcp_geterr(CLIENT *, struct rpc_err *);
+static bool_t          clnttcp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t          clnttcp_control(CLIENT *, uint_t, void *);
+static void            clnttcp_destroy(CLIENT *h);
+static bool_t          clnttcp_getreply(CLIENT *, xdrproc_t, void *,
+                               int, uint32_t *, uint32_t *, struct timeval *);
+static int             clnttcp_poll(CLIENT *, uint32_t);
+
+
+static struct clnt_ops tcp_ops = {
+       clnttcp_call,
+       clnttcp_abort,
+       clnttcp_geterr,
+       clnttcp_freeres,
+       clnttcp_destroy,
+       clnttcp_control,
+       clnttcp_getreply,
+       clnttcp_poll
+};
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr.  If *sockp non-negative then
+ * raddr is ignored.  The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+clnttcp_create(
+       struct sockaddr_in *raddr,
+       uint32_t prog,
+       uint32_t vers,
+       int *sockp,
+       uint_t sendsz,
+       uint_t recvsz)
+{
+       CLIENT *h;
+       struct ct_data *ct;
+       struct timeval now;
+       struct rpc_msg call_msg;
+
+       h  = (CLIENT *)mem_alloc(sizeof(CLIENT));
+       if (h == NULL) {
+               (void)fprintf(stderr, "clnttcp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       ct = (struct ct_data *)mem_alloc(sizeof(struct ct_data));
+       if (ct == NULL) {
+               (void)fprintf(stderr, "clnttcp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+
+       /*
+        * If no port number given ask the pmap for one
+        */
+       if (raddr->sin_port == 0) {
+               uint16_t port;
+               if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
+                       mem_free((void *)ct, sizeof(struct ct_data));
+                       mem_free((void *)h, sizeof(CLIENT));
+                       return ((CLIENT *)NULL);
+               }
+               raddr->sin_port = htons(port);
+       }
+
+       /*
+        * If no socket given, open one
+        */
+       if (*sockp < 0) {
+               *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+               (void)bindresvport(*sockp, (struct sockaddr_in *)0);
+               if ((*sockp < 0)
+                   || (connect(*sockp, (struct sockaddr *)raddr,
+                   sizeof(struct sockaddr_in)) < 0)) {
+                       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+                       rpc_createerr.cf_error.re_errno = errno;
+                       (void)close(*sockp);
+                       goto fooy;
+               }
+               ct->ct_closeit = TRUE;
+       } else {
+               ct->ct_closeit = FALSE;
+       }
+
+       /*
+        * Set up private data struct
+        */
+       ct->ct_sock = *sockp;
+       ct->ct_wait.tv_usec = 0;
+       ct->ct_waitset = FALSE;
+       ct->ct_addr = *raddr;
+
+       /*
+        * Initialize call message
+        */
+       (void)gettimeofday(&now, (struct timezone *)0);
+       call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+       call_msg.rm_direction = CALL;
+       call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       call_msg.rm_call.cb_prog = prog;
+       call_msg.rm_call.cb_vers = vers;
+
+       /*
+        * pre-serialize the staic part of the call msg and stash it away
+        */
+       xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
+           XDR_ENCODE);
+       if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
+               if (ct->ct_closeit) {
+                       (void)close(*sockp);
+               }
+               goto fooy;
+       }
+       ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
+       XDR_DESTROY(&(ct->ct_xdrs));
+
+       /*
+        * Create a client handle which uses xdrrec for serialization
+        * and authnone for authentication.
+        */
+       xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
+           (void *)ct, readtcp, writetcp);
+       h->cl_ops = &tcp_ops;
+       h->cl_private = (char *) ct;
+       h->cl_auth = authnone_create();
+       return (h);
+
+fooy:
+       /*
+        * Something goofed, free stuff and barf
+        */
+       mem_free((void *)ct, sizeof(struct ct_data));
+       mem_free((void *)h, sizeof(CLIENT));
+       return ((CLIENT *)NULL);
+}
+
+static enum clnt_stat
+clnttcp_call(
+       CLIENT *h,
+       uint32_t proc,
+       xdrproc_t xdr_args,
+       void * args_ptr,
+       xdrproc_t xdr_results,
+       void * results_ptr,
+       struct timeval timeout)
+{
+       struct ct_data *ct = (struct ct_data *) h->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+       struct rpc_msg reply_msg;
+       uint32_t x_id;
+       uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);        /* yuk */
+       bool_t shipnow;
+       int refreshes = 2;
+
+       if (!ct->ct_waitset) {
+               ct->ct_wait = timeout;
+       }
+
+       shipnow =
+           (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
+           && timeout.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+       xdrs->x_op = XDR_ENCODE;
+       ct->ct_error.re_status = RPC_SUCCESS;
+       x_id = ntohl(--(*msg_x_id));
+       if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
+           (! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
+           (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
+           (! (*xdr_args)(xdrs, args_ptr))) {
+               if (ct->ct_error.re_status == RPC_SUCCESS)
+                       ct->ct_error.re_status = RPC_CANTENCODEARGS;
+               (void)xdrrec_endofrecord(xdrs, TRUE);
+               return (ct->ct_error.re_status);
+       }
+       if (! xdrrec_endofrecord(xdrs, shipnow))
+               return (ct->ct_error.re_status = RPC_CANTSEND);
+       if (! shipnow)
+               return (RPC_SUCCESS);
+       /*
+        * Hack to provide rpc-based message passing
+        */
+       if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+               return(ct->ct_error.re_status = RPC_TIMEDOUT);
+       }
+
+
+       /*
+        * Keep receiving until we get a valid transaction id
+        */
+       xdrs->x_op = XDR_DECODE;
+       /* CONSTCOND */
+       while (TRUE) {
+               reply_msg.acpted_rply.ar_verf = _null_auth;
+               reply_msg.acpted_rply.ar_results.where = NULL;
+               reply_msg.acpted_rply.ar_results.proc = xdr_void;
+               if (! xdrrec_skiprecord(xdrs))
+                       return (ct->ct_error.re_status);
+               /* now decode and validate the response header */
+               if (! xdr_replymsg(xdrs, &reply_msg)) {
+                       if (ct->ct_error.re_status == RPC_SUCCESS)
+                               continue;
+                       return (ct->ct_error.re_status);
+               }
+               if (reply_msg.rm_xid == x_id)
+                       break;
+       }
+
+       /*
+        * process header
+        */
+       _seterr_reply(&reply_msg, &(ct->ct_error));
+       if (ct->ct_error.re_status == RPC_SUCCESS) {
+               if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
+                       ct->ct_error.re_status = RPC_AUTHERROR;
+                       ct->ct_error.re_why = AUTH_INVALIDRESP;
+               } else if (! (*xdr_results)(xdrs, results_ptr)) {
+                       if (ct->ct_error.re_status == RPC_SUCCESS)
+                               ct->ct_error.re_status = RPC_CANTDECODERES;
+               }
+               /* free verifier ... */
+               if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
+                       xdrs->x_op = XDR_FREE;
+                       (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
+               }
+       }  /* end successful completion */
+       else {
+               /* maybe our credentials need to be refreshed ... */
+               if (refreshes-- && AUTH_REFRESH(h->cl_auth))
+                       goto call_again;
+       }  /* end of unsuccessful completion */
+       return (ct->ct_error.re_status);
+}
+
+static void
+clnttcp_geterr(
+       CLIENT *h,
+       struct rpc_err *errp)
+{
+       struct ct_data *ct =
+           (struct ct_data *) h->cl_private;
+
+       *errp = ct->ct_error;
+}
+
+static bool_t
+clnttcp_freeres(
+       CLIENT *cl,
+       xdrproc_t xdr_res,
+       void * res_ptr)
+{
+       struct ct_data *ct = (struct ct_data *)cl->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/* ARGSUSED */
+static void
+clnttcp_abort(CLIENT *c)
+{
+}
+
+static bool_t
+clnttcp_control(
+       CLIENT *cl,
+       uint_t request,
+       void *info)
+{
+       struct ct_data *ct = (struct ct_data *)cl->cl_private;
+
+       switch (request) {
+       case CLSET_TIMEOUT:
+               ct->ct_wait = *(struct timeval *)info;
+               ct->ct_waitset = TRUE;
+               break;
+       case CLGET_TIMEOUT:
+               *(struct timeval *)info = ct->ct_wait;
+               break;
+       case CLGET_SERVER_ADDR:
+               *(struct sockaddr_in *)info = ct->ct_addr;
+               break;
+       default:
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+
+static void
+clnttcp_destroy(
+       CLIENT *h)
+{
+       struct ct_data *ct =
+           (struct ct_data *) h->cl_private;
+
+       if (ct->ct_closeit) {
+               (void)close(ct->ct_sock);
+       }
+       XDR_DESTROY(&(ct->ct_xdrs));
+       mem_free((void *)ct, sizeof(struct ct_data));
+       mem_free((void *)h, sizeof(CLIENT));
+}
+
+/*
+ * Interface between xdr serializer and tcp connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readtcp(
+       struct ct_data *ct,
+       char *buf,
+       int len)
+{
+#ifdef FD_SETSIZE
+       fd_set mask;
+       fd_set readfds;
+
+       if (len == 0)
+               return (0);
+       FD_ZERO(&mask);
+       FD_SET(ct->ct_sock, &mask);
+#else
+       int mask = 1 << (ct->ct_sock);
+       int readfds;
+
+       if (len == 0)
+               return (0);
+
+#endif /* def FD_SETSIZE */
+       /* CONSTCOND */
+       while (TRUE) {
+               readfds = mask;
+               switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
+                              &(ct->ct_wait))) {
+               case 0:
+                       ct->ct_error.re_status = RPC_TIMEDOUT;
+                       return (-1);
+
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       ct->ct_error.re_status = RPC_CANTRECV;
+                       ct->ct_error.re_errno = errno;
+                       return (-1);
+               }
+               break;
+       }
+       switch (len = read(ct->ct_sock, buf, len)) {
+
+       case 0:
+               /* premature eof */
+               ct->ct_error.re_errno = ECONNRESET;
+               ct->ct_error.re_status = RPC_CANTRECV;
+               len = -1;  /* it's really an error */
+               break;
+
+       case -1:
+               ct->ct_error.re_errno = errno;
+               ct->ct_error.re_status = RPC_CANTRECV;
+               break;
+       }
+       return (len);
+}
+
+static int
+writetcp(
+       struct ct_data *ct,
+       char *buf,
+       int len)
+{
+       int i, cnt;
+
+       for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+               if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
+                       ct->ct_error.re_errno = errno;
+                       ct->ct_error.re_status = RPC_CANTSEND;
+                       return (-1);
+               }
+       }
+       return (len);
+}
+/* ARGSUSED */
+static bool_t
+clnttcp_getreply(
+        CLIENT *cl,
+        xdrproc_t xproc,
+        void *xres,
+       int cnt,
+       uint32_t *xids,
+        uint32_t *xid,
+       struct timeval *tv)
+{
+        return (FALSE);
+}
+/* ARGSUSED */
+static int
+clnttcp_poll(
+        CLIENT *cl,
+        uint32_t usec)
+{
+        return (-1);
+}
+
diff --git a/TBBT/trace_play/rpc/clnt_udp.c b/TBBT/trace_play/rpc/clnt_udp.c
new file mode 100755 (executable)
index 0000000..d362f10
--- /dev/null
@@ -0,0 +1,510 @@
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)clnt_udp.c     2.1     97/10/23";
+#endif
+/* @(#)clnt_udp.c      2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_udp.c, Implements a UDP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifndef FreeBSD
+#include <stropts.h>
+#endif /* ndef Free BSD */
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+#include <errno.h>
+#include "rpc/pmap_clnt.h"
+
+/* 
+ * Private data kept per client handle
+ */
+struct cu_data {
+       int                cu_sock;
+       bool_t             cu_closeit;
+       struct sockaddr_in cu_raddr;
+       int                cu_rlen;
+       struct timeval     cu_wait;
+       struct timeval     cu_total;
+       struct rpc_err     cu_error;
+       XDR                cu_outxdrs;
+       uint_t             cu_xdrpos;
+       uint_t             cu_sendsz;
+       char               *cu_outbuf;
+       uint_t             cu_recvsz;
+       char               cu_inbuf[1];
+};
+
+/*
+ * UDP bases client side rpc operations
+ */
+static enum clnt_stat  clntudp_call(CLIENT *, uint32_t, xdrproc_t, void *,
+                                       xdrproc_t, void *, struct timeval);
+static void            clntudp_abort(CLIENT *);
+static void            clntudp_geterr(CLIENT *, struct rpc_err *);
+static bool_t          clntudp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t          clntudp_control(CLIENT *, uint_t, void *);
+static void            clntudp_destroy(CLIENT *);
+static bool_t          clntudp_getreply(CLIENT *, xdrproc_t, void *,
+                               int, uint32_t *, uint32_t *, struct timeval *);
+static int             clntudp_poll(CLIENT *, uint32_t);
+
+static struct clnt_ops udp_ops = {
+       clntudp_call,
+       clntudp_abort,
+       clntudp_geterr,
+       clntudp_freeres,
+       clntudp_destroy,
+       clntudp_control,
+       clntudp_getreply,
+       clntudp_poll
+};
+
+/*
+ * Create a UDP based client handle.
+ * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If raddr->sin_port is 0 a binder on the remote machine
+ * is consulted for the correct port number.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ *     Caller may wish to set this something more useful.
+ *
+ * wait is the amount of time used between retransmitting a call if
+ * no response has been heard;  retransmition occurs until the actual
+ * rpc call times out.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received.
+ */
+CLIENT *
+clntudp_bufcreate(
+       struct sockaddr_in *raddr,
+       uint32_t program,
+       uint32_t version,
+       struct timeval wait,
+       int *sockp,
+       uint_t sendsz,
+       uint_t recvsz)
+{
+       CLIENT *cl;
+       struct cu_data *cu;
+       struct timeval now;
+       struct rpc_msg call_msg;
+
+       cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
+       if (cl == NULL) {
+               (void) fprintf(stderr, "clntudp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       sendsz = ((sendsz + 3) / 4) * 4;
+       recvsz = ((recvsz + 3) / 4) * 4;
+       cu = (struct cu_data *)mem_alloc(sizeof(struct cu_data) +
+                                               sendsz + recvsz);
+       if (cu == NULL) {
+               (void) fprintf(stderr, "clntudp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       cu->cu_outbuf = &cu->cu_inbuf[recvsz];
+
+       (void)gettimeofday(&now, (struct timezone *)0);
+       if (raddr->sin_port == 0) {
+               uint16_t port;
+               if ((port =
+                   pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
+                       goto fooy;
+               }
+               raddr->sin_port = htons(port);
+       }
+       cl->cl_ops = &udp_ops;
+       cl->cl_private = (char *)cu;
+       cu->cu_raddr = *raddr;
+       cu->cu_rlen = sizeof (cu->cu_raddr);
+       cu->cu_wait = wait;
+       cu->cu_total.tv_sec = -1;
+       cu->cu_total.tv_usec = -1;
+       cu->cu_sendsz = sendsz;
+       cu->cu_recvsz = recvsz;
+       call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+       call_msg.rm_direction = CALL;
+       call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       call_msg.rm_call.cb_prog = program;
+       call_msg.rm_call.cb_vers = version;
+       xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
+           sendsz, XDR_ENCODE);
+       if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
+               goto fooy;
+       }
+       cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
+       if (*sockp < 0) {
+#if defined(O_NONBLOCK)
+               int flags;
+#elif defined(FIONBIO)
+               int dontblock = 1;
+#endif
+
+               *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+               if (*sockp < 0) {
+                       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+                       rpc_createerr.cf_error.re_errno = errno;
+                       goto fooy;
+               }
+               /* attempt to bind to prov port */
+               (void)bindresvport(*sockp, (struct sockaddr_in *)0);
+               /* the sockets rpc controls are non-blocking */
+#if defined(O_NONBLOCK)
+                flags = fcntl(*sockp, F_GETFL, 0) | O_NONBLOCK;
+                (void)fcntl(*sockp, F_SETFL, flags);
+#elif defined(FIONBIO)
+                (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
+#endif
+               cu->cu_closeit = TRUE;
+       } else {
+               cu->cu_closeit = FALSE;
+       }
+       cu->cu_sock = *sockp;
+       cl->cl_auth = authnone_create();
+       return (cl);
+fooy:
+       if (cu)
+               mem_free((void *)cu, sizeof(struct cu_data) + sendsz + recvsz);
+       if (cl)
+               mem_free((void *)cl, sizeof(CLIENT));
+       return ((CLIENT *)NULL);
+}
+
+CLIENT *
+clntudp_create(
+       struct sockaddr_in *raddr,
+       uint32_t program,
+       uint32_t version,
+       struct timeval wait,
+       int *sockp)
+{
+
+       return(clntudp_bufcreate(raddr, program, version, wait, sockp,
+           UDPMSGSIZE, UDPMSGSIZE));
+}
+
+static enum clnt_stat 
+clntudp_call(
+       CLIENT  *cl,
+       uint32_t        proc,
+       xdrproc_t       xargs,
+       void *          argsp,
+       xdrproc_t       xresults,
+       void *          resultsp,
+       struct timeval  utimeout)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       XDR *xdrs;
+       int outlen;
+       int inlen;
+#if defined(AIX)
+       size_t fromlen;
+#else
+       int fromlen;
+#endif
+#ifdef FD_SETSIZE
+       fd_set readfds;
+       fd_set mask;
+#else
+       int readfds;
+       int mask;
+#endif /* def FD_SETSIZE */
+       struct sockaddr_in from;
+       struct rpc_msg reply_msg;
+       XDR reply_xdrs;
+       struct timeval time_waited;
+       bool_t ok;
+       int nrefreshes = 2;     /* number of times to refresh cred */
+       struct timeval timeout;
+
+       if (cu->cu_total.tv_usec == -1) {
+               timeout = utimeout;     /* use supplied timeout */
+       } else {
+               timeout = cu->cu_total; /* use default timeout */
+       }
+
+       time_waited.tv_sec = 0;
+       time_waited.tv_usec = 0;
+call_again:
+       xdrs = &(cu->cu_outxdrs);
+       xdrs->x_op = XDR_ENCODE;
+       XDR_SETPOS(xdrs, cu->cu_xdrpos);
+       /*
+        * the transaction is the first thing in the out buffer
+        */
+       (*(uint32_t *)(cu->cu_outbuf))++;
+       if ((! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
+           (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+           (! (*xargs)(xdrs, argsp)))
+               return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+       outlen = (int)XDR_GETPOS(xdrs);
+
+send_again:
+       if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
+           (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
+           != outlen) {
+               cu->cu_error.re_errno = errno;
+               return (cu->cu_error.re_status = RPC_CANTSEND);
+       }
+
+       /*
+        * Hack to provide rpc-based message passing
+        */
+       if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+               return (cu->cu_error.re_status = RPC_TIMEDOUT);
+       }
+       /*
+        * sub-optimal code appears here because we have
+        * some clock time to spare while the packets are in flight.
+        * (We assume that this is actually only executed once.)
+        */
+       reply_msg.acpted_rply.ar_verf = _null_auth;
+       reply_msg.acpted_rply.ar_results.where = resultsp;
+       reply_msg.acpted_rply.ar_results.proc = xresults;
+#ifdef FD_SETSIZE
+       FD_ZERO(&mask);
+       FD_SET(cu->cu_sock, &mask);
+#else
+       mask = 1 << cu->cu_sock;
+#endif /* def FD_SETSIZE */
+       for (;;) {
+               readfds = mask;
+               switch (select(_rpc_dtablesize(), &readfds, NULL, 
+                              NULL, &(cu->cu_wait))) {
+
+               case 0:
+                       time_waited.tv_sec += cu->cu_wait.tv_sec;
+                       time_waited.tv_usec += cu->cu_wait.tv_usec;
+                       while (time_waited.tv_usec >= 1000000) {
+                               time_waited.tv_sec++;
+                               time_waited.tv_usec -= 1000000;
+                       }
+                       if ((time_waited.tv_sec < timeout.tv_sec) ||
+                               ((time_waited.tv_sec == timeout.tv_sec) &&
+                               (time_waited.tv_usec < timeout.tv_usec)))
+                               goto send_again;        
+                       return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
+               /*
+                * buggy in other cases because time_waited is not being
+                * updated.
+                */
+               case -1:
+                       if (errno == EINTR)
+                               continue;       
+                       cu->cu_error.re_errno = errno;
+                       return (cu->cu_error.re_status = RPC_CANTRECV);
+               }
+               do {
+                       fromlen = sizeof(struct sockaddr);
+                       inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
+                               (int) cu->cu_recvsz, 0,
+                               (struct sockaddr *)&from, &fromlen);
+               } while (inlen < 0 && errno == EINTR);
+               if (inlen < 0) {
+                       if (errno == EWOULDBLOCK)
+                               continue;       
+                       cu->cu_error.re_errno = errno;
+                       return (cu->cu_error.re_status = RPC_CANTRECV);
+               }
+               if (inlen < sizeof(uint32_t))
+                       continue;       
+               /* see if reply transaction id matches sent id */
+               if (*((uint32_t *)(cu->cu_inbuf)) != *((uint32_t *)(cu->cu_outbuf)))
+                       continue;       
+               /* we now assume we have the proper reply */
+               break;
+       }
+
+       /*
+        * now decode and validate the response
+        */
+       xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)inlen, XDR_DECODE);
+       ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+       /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
+       if (ok) {
+               _seterr_reply(&reply_msg, &(cu->cu_error));
+               if (cu->cu_error.re_status == RPC_SUCCESS) {
+                       if (! AUTH_VALIDATE(cl->cl_auth,
+                               &reply_msg.acpted_rply.ar_verf)) {
+                               cu->cu_error.re_status = RPC_AUTHERROR;
+                               cu->cu_error.re_why = AUTH_INVALIDRESP;
+                       }
+                       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
+                               xdrs->x_op = XDR_FREE;
+                               (void)xdr_opaque_auth(xdrs,
+                                   &(reply_msg.acpted_rply.ar_verf));
+                       } 
+               }  /* end successful completion */
+               else {
+                       /* maybe our credentials need to be refreshed ... */
+                       if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
+                               nrefreshes--;
+                               goto call_again;
+                       }
+               }  /* end of unsuccessful completion */
+       }  /* end of valid reply message */
+       else {
+               cu->cu_error.re_status = RPC_CANTDECODERES;
+       }
+       return (cu->cu_error.re_status);
+}
+
+static void
+clntudp_geterr(
+       CLIENT *cl,
+       struct rpc_err *errp)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       *errp = cu->cu_error;
+}
+
+
+static bool_t
+clntudp_freeres(
+       CLIENT *cl,
+       xdrproc_t xdr_res,
+       void * res_ptr)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       XDR *xdrs = &(cu->cu_outxdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/* ARGSUSED */
+static void 
+clntudp_abort(
+       CLIENT *h)
+{
+}
+
+static bool_t
+clntudp_control(
+       CLIENT *cl,
+       uint_t request,
+       void *info)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       switch (request) {
+       case CLSET_TIMEOUT:
+               cu->cu_total = *(struct timeval *)info;
+               break;
+       case CLGET_TIMEOUT:
+               *(struct timeval *)info = cu->cu_total;
+               break;
+       case CLSET_RETRY_TIMEOUT:
+               cu->cu_wait = *(struct timeval *)info;
+               break;
+       case CLGET_RETRY_TIMEOUT:
+               *(struct timeval *)info = cu->cu_wait;
+               break;
+       case CLGET_SERVER_ADDR:
+               *(struct sockaddr_in *)info = cu->cu_raddr;
+               break;
+       default:
+               return (FALSE);
+       }
+       return (TRUE);
+}
+       
+static void
+clntudp_destroy(
+       CLIENT *cl)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       if (cu->cu_closeit) {
+               (void)close(cu->cu_sock);
+       }
+       XDR_DESTROY(&(cu->cu_outxdrs));
+       mem_free((void *)cu, (sizeof(struct cu_data) + cu->cu_sendsz + cu->cu_recvsz));
+       mem_free((void *)cl, sizeof(CLIENT));
+}
+
+/* ARGSUSED */
+static bool_t
+clntudp_getreply(
+       CLIENT *cl,
+       xdrproc_t xproc,
+       void *xres,
+       int cnt,
+       uint32_t *xids,
+       uint32_t *xid,
+       struct timeval *tv)
+{
+       return (FALSE);
+}
+
+/* ARGSUSED */
+static int
+clntudp_poll(
+       CLIENT *cl,
+       uint32_t usec)
+{
+       return (-1);
+}
diff --git a/TBBT/trace_play/rpc/get_myaddress.c b/TBBT/trace_play/rpc/get_myaddress.c
new file mode 100755 (executable)
index 0000000..37bb930
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef lint
+static char sfs_get_myaddress_id[] = "@(#)get_myaddress.c     2.1     97/10/23";
+#endif
+/* @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * get_myaddress.c
+ *
+ * Get client's IP address via ioctl.  This avoids using the yellowpages.
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> 
+#ifndef FreeBSD
+#include <stropts.h>   
+#endif /* ndef FreeBSD */
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_prot.h"
+#include "rpc/osdep.h"
+#include <sys/utsname.h>
+
+#ifdef FreeBSD
+#include <netdb.h>     
+#define MY_NAMELEN 256
+static char myhostname[MY_NAMELEN];
+#endif /* def FreeBSD */
+
+void
+get_myaddress(
+       struct sockaddr_in *addr)
+{
+       int s;
+       char buf[BUFSIZ];
+       struct ifconf ifc;
+       struct ifreq ifreq, *ifr;
+       int len;        
+       struct sockaddr_in tmp_addr;
+#ifdef _AIX
+       char    *cp, *cplim;
+#endif
+
+#ifdef FreeBSD
+        static struct in_addr *my_addr;
+        struct hostent *ent;     
+
+       /* In FreeBSD, SIOCGIFCONF provides AF_LINK information, not AF_INET. */
+        gethostname(myhostname, MY_NAMELEN);
+        ent = gethostbyname(myhostname);
+        if (ent == NULL) {
+            fprintf(stderr, "lookup on server's name failed\n");
+            exit(1);
+        }
+        bzero(addr, sizeof(struct sockaddr_in));
+        my_addr = (struct in_addr *)(*(ent->h_addr_list));
+        bcopy(my_addr, &(addr->sin_addr.s_addr), sizeof(struct in_addr));
+        addr->sin_family = AF_INET;
+        addr->sin_port = htons(PMAPPORT);
+        return;                
+#endif /* def FreeBSD */
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+           perror("get_myaddress: socket");
+           exit(1);
+       }
+       ifc.ifc_len = sizeof (buf);
+       ifc.ifc_buf = buf;
+       if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+               perror("get_myaddress: ioctl (get interface configuration)");
+               exit(1);
+       }
+       ifr = ifc.ifc_req;
+#ifdef _AIX
+       cplim = buf + ifc.ifc_len;
+       for (cp = buf; cp < cplim;
+            cp += MAX(sizeof(struct ifreq),
+                      (sizeof (ifr->ifr_name) +
+                       MAX((ifr->ifr_addr).sa_len, sizeof(ifr->ifr_addr))))) {
+               ifr = (struct ifreq *)cp;
+#else
+       for (len = ifc.ifc_len; len; len -= sizeof(ifreq), ifr++) {
+#endif
+               ifreq = *ifr;
+                /* Save address, since SIOCGIFFLAGS may scribble over *ifr. */
+                tmp_addr = *((struct sockaddr_in *)&ifr->ifr_addr);
+               if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                       perror("get_myaddress: ioctl");
+                       exit(1);
+               }
+               if ((ifreq.ifr_flags & IFF_UP) &&
+                   ifr->ifr_addr.sa_family == AF_INET) {
+                       *addr = tmp_addr;
+                       addr->sin_port = htons(PMAPPORT);
+                       break;
+               }
+       }
+       (void) close(s);
+}
+
+/*
+ * A generic gethostname
+ */
+int
+getmyhostname(char *name, int namelen)
+{
+#if !defined(HAS_GETHOSTNAME)
+        struct utsname utsname;
+       int ret;
+
+        ret = uname(&utsname);
+       if (ret == -1)
+               return (-1);
+        (void) strncpy(name, utsname.nodename, namelen);
+       return (0);
+#else
+       return(gethostname(name, namelen));
+#endif
+}
diff --git a/TBBT/trace_play/rpc/getrpcent.c b/TBBT/trace_play/rpc/getrpcent.c
new file mode 100755 (executable)
index 0000000..2649af6
--- /dev/null
@@ -0,0 +1,250 @@
+#ifndef lint
+static char sfs_getrpcent_id[] = "@(#)getrpcent.c     2.1     97/10/23";
+#endif
+/* @(#)getrpcent.c     2.2 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static  char sccsid[] = "@(#)getrpcent.c 1.9 87/08/11  Copyr 1984 Sun Micro";
+#endif
+/*
+ *  Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "rpc/rpc.h"
+#include "rpc/netdb.h"
+#include "rpc/osdep.h"
+
+/*
+ * Internet version.
+ */
+struct rpcdata {
+       FILE    *rpcf;
+       char    *current;
+       int     currentlen;
+       int     stayopen;
+#define        MAXALIASES      35
+       char    *rpc_aliases[MAXALIASES];
+       struct  rpcent rpc;
+       char    line[BUFSIZ+1];
+       char    *domain;
+} *rpcdata;
+
+extern void setrpcent(int);
+extern void endrpcent(void);
+static struct rpcent *interpret(char *, int);
+
+static char RPCDB[] = "/etc/rpc";
+
+static struct rpcdata *
+_rpcdata(void)
+{
+       register struct rpcdata *d = rpcdata;
+
+       if (d == 0) {
+               d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata));
+               rpcdata = d;
+       }
+       return (d);
+}
+
+struct rpcent *
+getrpcbynumber(
+       int number)
+{
+       register struct rpcdata *d = _rpcdata();
+       register struct rpcent *p;
+
+       if (d == 0)
+               return (0);
+       setrpcent(0);
+       while ((p = getrpcent()) != NULL) {
+               if (p->r_number == number)
+                       break;
+       }
+       endrpcent();
+       return (p);
+}
+
+struct rpcent *
+getrpcbyname(
+       char *name)
+{
+       struct rpcent *rpc;
+       char **rp;
+
+       setrpcent(0);
+       while((rpc = getrpcent()) != NULL) {
+               if (strcmp(rpc->r_name, name) == 0)
+                       return (rpc);
+               for (rp = rpc->r_aliases; *rp != NULL; rp++) {
+                       if (strcmp(*rp, name) == 0)
+                               return (rpc);
+               }
+       }
+       endrpcent();
+       return (NULL);
+}
+
+void
+setrpcent(
+       int f)
+{
+       register struct rpcdata *d = _rpcdata();
+
+       if (d == 0)
+               return;
+       if (d->rpcf == NULL)
+               d->rpcf = fopen(RPCDB, "r");
+       else
+               rewind(d->rpcf);
+       if (d->current)
+               free(d->current);
+       d->current = NULL;
+       d->stayopen |= f;
+}
+
+void
+endrpcent(void)
+{
+       register struct rpcdata *d = _rpcdata();
+
+       if (d == 0)
+               return;
+       if (d->current && !d->stayopen) {
+               free(d->current);
+               d->current = NULL;
+       }
+       if (d->rpcf && !d->stayopen) {
+               fclose(d->rpcf);
+               d->rpcf = NULL;
+       }
+}
+
+struct rpcent *
+getrpcent(void)
+{
+       register struct rpcdata *d = _rpcdata();
+
+       if (d == 0)
+               return(NULL);
+       if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL)
+               return (NULL);
+       if (fgets(d->line, BUFSIZ, d->rpcf) == NULL)
+               return (NULL);
+       return (interpret(d->line, strlen(d->line)));
+}
+
+static struct rpcent *
+interpret(
+       char *val,
+       int len)
+{
+       register struct rpcdata *d = _rpcdata();
+       char *p;
+       register char *cp, **q;
+
+       if (d == 0)
+               return (NULL);
+       strncpy(d->line, val, len);
+       p = d->line;
+       d->line[len] = '\n';
+       if (*p == '#')
+               return (getrpcent());
+       cp = strchr(p, '#');
+       if (cp == NULL) {
+               cp = strchr(p, '\n');
+               if (cp == NULL)
+                       return (getrpcent());
+       }
+       *cp = '\0';
+       cp = strchr(p, ' ');
+       if (cp == NULL) {
+               cp = strchr(p, '\t');
+               if (cp == NULL)
+                       return (getrpcent());
+       }
+       *cp++ = '\0';
+       /* THIS STUFF IS INTERNET SPECIFIC */
+       d->rpc.r_name = d->line;
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       d->rpc.r_number = atoi(cp);
+       q = d->rpc.r_aliases = d->rpc_aliases;
+       cp = strchr(p, ' ');
+       if (cp != NULL)
+               *cp++ = '\0';
+       else {
+               cp = strchr(p, '\t');
+               if (cp != NULL)
+                       *cp++ = '\0';
+       }
+       while (cp && *cp) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               if (q < &(d->rpc_aliases[MAXALIASES - 1]))
+                       *q++ = cp;
+               cp = strchr(p, ' ');
+               if (cp != NULL)
+                       *cp++ = '\0';
+               else {
+                       cp = strchr(p, '\t');
+                       if (cp != NULL)
+                               *cp++ = '\0';
+               }
+       }
+       *q = NULL;
+       return (&d->rpc);
+}
diff --git a/TBBT/trace_play/rpc/getrpcport.c b/TBBT/trace_play/rpc/getrpcport.c
new file mode 100755 (executable)
index 0000000..6434082
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef lint
+static char sfs_getrpcport_id[] = "@(#)getrpcport.c     2.1     97/10/23";
+#endif
+/* @(#)getrpcport.c    2.1 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static  char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI";
+#endif
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include <netdb.h>
+#include "rpc/osdep.h"
+
+getrpcport(host, prognum, versnum, proto)
+       char *host;
+{
+       struct sockaddr_in addr;
+       struct hostent *hp;
+
+       if ((hp = gethostbyname(host)) == NULL)
+               return (0);
+       memmove((char *) &addr.sin_addr, hp->h_addr, hp->h_length);
+       addr.sin_family = AF_INET;
+       addr.sin_port =  0;
+       return (pmap_getport(&addr, prognum, versnum, proto));
+}
diff --git a/TBBT/trace_play/rpc/netdb.h b/TBBT/trace_play/rpc/netdb.h
new file mode 100755 (executable)
index 0000000..a3a96fc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * @(#)netdb.h     2.1     97/10/23
+ */
+/* @(#)netdb.h 2.1 88/07/29 3.9 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*     @(#)rpc.h 1.8 87/07/24 SMI      */
+
+/* Really belongs in <netdb.h> */
+
+struct rpcent {
+      char    *r_name;        /* name of server for this rpc program */
+      char    **r_aliases;    /* alias list */
+      int     r_number;       /* rpc program number */
+};
+
+extern struct rpcent *getrpcbynumber(int);
+extern struct rpcent *getrpcbyname(char *);
+extern struct rpcent *getrpcent(void);
diff --git a/TBBT/trace_play/rpc/osdep.h b/TBBT/trace_play/rpc/osdep.h
new file mode 100755 (executable)
index 0000000..67598d0
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * @(#)osdep.h     2.1     97/10/23
+ */
+/*      @(#)types.h 1.18 87/07/24 SMI      */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+#ifndef __RPC_OSDEP_H__
+#define __RPC_OSDEP_H__
+
+/*
+ * OS dependancies
+ *
+ * These are non-XPG4.2 standard include files, if not compiling in a
+ * strict environment simply #include them, otherwise we must define
+ * our own missing pieces.  The definitions below are specific to
+ * Solaris 2.X and may be different on other systems.
+ */
+
+#if !defined(_XOPEN_SOURCE) || defined (OSF1) || defined(AIX)
+#if defined(SVR4)
+#define BSD_COMP
+#endif
+#if defined(AIX)
+#include <sys/param.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#else
+#if defined(_BIG_ENDIAN) && !defined(ntohl) && !defined(lint)
+/* big-endian */
+#define ntohl(x)        (x)
+#define ntohs(x)        (x)
+#define htonl(x)        (x)
+#define htons(x)        (x)
+#elif !defined(ntohl) /* little-endian */
+extern unsigned short ntohs(unsigned short ns);
+extern unsigned short htons(unsigned short hs);
+extern unsigned long  ntohl(unsigned long nl);
+extern unsigned long  htonl(unsigned long hl);
+#endif
+/*
+ * Internet address
+ *     This definition contains obsolete fields for compatibility
+ *     with SunOS 3.x and 4.2bsd.  The presence of subnets renders
+ *     divisions into fixed fields misleading at best.  New code
+ *     should use only the s_addr field.
+ */
+struct in_addr {
+       union {
+               struct { unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b;
+               struct { unsigned short s_w1, s_w2; } S_un_w;
+               unsigned long S_addr;
+       } S_un;
+#define s_addr  S_un.S_addr             /* should be used for all code */
+#define s_host  S_un.S_un_b.s_b2        /* OBSOLETE: host on imp */
+#define s_net   S_un.S_un_b.s_b1        /* OBSOLETE: network */
+#define s_imp   S_un.S_un_w.s_w2        /* OBSOLETE: imp */
+#define s_impno S_un.S_un_b.s_b4        /* OBSOLETE: imp # */
+#define s_lh    S_un.S_un_b.s_b3        /* OBSOLETE: logical host */
+};
+
+struct sockaddr_in {
+        short   sin_family;
+        unsigned short sin_port;
+        struct  in_addr sin_addr;
+        char    sin_zero[8];
+};
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+       uint16_t sa_family;             /* address family */
+       char    sa_data[14];            /* up to 14 bytes of direct address */
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's.  All interface ioctl's must have parameter
+ * definitions which begin with ifr_name.  The
+ * remainder may be interface specific.
+ */
+struct ifreq {
+#define        IFNAMSIZ        16
+       char    ifr_name[IFNAMSIZ];             /* if name, e.g. "en0" */
+       union {
+               struct  sockaddr ifru_addr;
+               struct  sockaddr ifru_dstaddr;
+               char    ifru_oname[IFNAMSIZ];   /* other if name */
+               struct  sockaddr ifru_broadaddr;
+               short   ifru_flags;
+               int     ifru_metric;
+               char    ifru_data[1];           /* interface dependent data */
+               char    ifru_enaddr[6];
+               int     if_muxid[2];            /* mux id's for arp and ip */
+
+               /* Struct for FDDI ioctl's */
+               struct ifr_dnld_reqs {
+                       void    *v_addr;
+                       void    *m_addr;
+                       void    *ex_addr;
+                       uint_t  size;
+               } ifru_dnld_req;
+
+               /* Struct for FDDI stats */
+               struct ifr_fddi_stats {
+                       uint_t  stat_size;
+                       void    *fddi_stats;
+               } ifru_fddi_stat;
+
+               struct ifr_netmapents {
+                       uint_t  map_ent_size,   /* size of netmap structure */
+                               entry_number;   /* index into netmap list */
+                       void    *fddi_map_ent;  /* pointer to user structure */
+               } ifru_netmapent;
+
+               /* Field for generic ioctl for fddi */
+
+               struct ifr_fddi_gen_struct {
+                       int     ifru_fddi_gioctl; /* field for gen ioctl */
+                       void    *ifru_fddi_gaddr; /* Generic ptr to a field */
+               } ifru_fddi_gstruct;
+
+       } ifr_ifru;
+
+#define        ifr_addr        ifr_ifru.ifru_addr      /* address */
+#define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
+#define        ifr_oname       ifr_ifru.ifru_oname     /* other if name */
+#define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address */
+#define        ifr_flags       ifr_ifru.ifru_flags     /* flags */
+#define        ifr_metric      ifr_ifru.ifru_metric    /* metric */
+#define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
+#define        ifr_enaddr      ifr_ifru.ifru_enaddr    /* ethernet address */
+
+/* FDDI specific */
+#define        ifr_dnld_req    ifr_ifru.ifru_dnld_req
+#define        ifr_fddi_stat   ifr_ifru.ifru_fddi_stat
+#define        ifr_fddi_netmap ifr_ifru.ifru_netmapent /* FDDI network map entries */
+#define        ifr_fddi_gstruct ifr_ifru.ifru_fddi_gstruct
+
+#define        ifr_ip_muxid    ifr_ifru.if_muxid[0]
+#define        ifr_arp_muxid   ifr_ifru.if_muxid[1]
+};
+
+struct ifconf {
+       int     ifc_len;                /* size of associated buffer */
+       union {
+               void    *ifcu_buf;
+               struct  ifreq *ifcu_req;
+       } ifc_ifcu;
+#define        ifc_buf ifc_ifcu.ifcu_buf       /* buffer address */
+#define        ifc_req ifc_ifcu.ifcu_req       /* array of structures returned */
+};
+
+#define        AF_INET                 2
+#define        IPPROTO_TCP             6
+#define        IPPROTO_UDP             17
+#define        IPPORT_RESERVED         1024
+#define        SOCK_DGRAM              1
+#define        SOCK_STREAM             2
+#define        SO_SNDBUF               0x1001
+#define        SO_RCVBUF               0x1002
+#define        SOL_SOCKET              0xffff
+#define        INADDR_ANY              (uint32_t)0x00000000
+#define        IFF_BROADCAST           0x2
+#define        IFF_UP                  0x1
+
+#define        IOCPARM_MASK    0xff
+#define        IOC_OUT         0x40000000
+#define        IOC_IN          0x80000000
+#define        IOC_INOUT       (IOC_IN|IOC_OUT)
+#define        _IOWR(x, y, t) \
+       (IOC_INOUT|((((int)sizeof (t))&IOCPARM_MASK)<<16)|(x<<8)|y)
+#define        SIOCGIFCONF             _IOWR('i', 20, struct ifconf)
+#define        SIOCGIFFLAGS    _IOWR('i', 17, struct ifreq)
+#define        SIOCGIFBRDADDR  _IOWR('i', 23, struct ifreq)
+
+extern int accept(int, struct sockaddr *, int *);
+extern int bind(int, struct sockaddr *, int);
+extern int connect(int, struct sockaddr *, int);
+extern int getsockname(int, struct sockaddr *, int *);
+extern int getsockopt(int, int, int, char *, int *);
+extern int listen(int, int);
+extern int recvfrom(int, char *, int, int, struct sockaddr *, int *);
+extern int sendto(int, const char *, int, int, const struct sockaddr *, int);
+extern int setsockopt(int, int, int, const char *, int);
+extern int socket(int, int, int);
+extern unsigned long inet_netof(struct in_addr);
+extern struct in_addr inet_makeaddr(int, int);
+
+#endif /* _XOPEN_SOURCE */
+
+#endif /* __RPC_OSDEP_H__ */
diff --git a/TBBT/trace_play/rpc/pmap_clnt.c b/TBBT/trace_play/rpc/pmap_clnt.c
new file mode 100755 (executable)
index 0000000..b2de53f
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef lint
+static char sfs_pmap_clnt_id[] = "@(#)pmap_clnt.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_clnt.c     2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_clnt.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_prot.h"
+#include "rpc/pmap_clnt.h"
+
+static struct timeval timeout = { 5, 0 };
+static struct timeval tottimeout = { 60, 0 };
+
+extern void get_myaddress(struct sockaddr_in *addr);
+
+/*
+ * Set a mapping between program,version and port.
+ * Calls the pmap service remotely to do the mapping.
+ */
+bool_t
+pmap_set(
+       uint32_t program,
+       uint32_t version,
+       int protocol,
+       uint16_t port)
+{
+       struct sockaddr_in myaddress;
+       int socket = -1;
+       register CLIENT *client;
+       struct pmap parms;
+       bool_t rslt;
+
+       get_myaddress(&myaddress);
+       client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
+           timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+       if (client == (CLIENT *)NULL)
+               return (FALSE);
+       parms.pm_prog = program;
+       parms.pm_vers = version;
+       parms.pm_prot = protocol;
+       parms.pm_port = port;
+       if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
+           tottimeout) != RPC_SUCCESS) {
+               clnt_perror(client, "Cannot register service");
+               return (FALSE);
+       }
+       CLNT_DESTROY(client);
+       (void)close(socket);
+       return (rslt);
+}
+
+/*
+ * Remove the mapping between program,version and port.
+ * Calls the pmap service remotely to do the un-mapping.
+ */
+bool_t
+pmap_unset(
+       uint32_t program,
+       uint32_t version)
+{
+       struct sockaddr_in myaddress;
+       int socket = -1;
+       register CLIENT *client;
+       struct pmap parms;
+       bool_t rslt;
+
+       get_myaddress(&myaddress);
+       client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
+           timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+       if (client == (CLIENT *)NULL)
+               return (FALSE);
+       parms.pm_prog = program;
+       parms.pm_vers = version;
+       parms.pm_port = parms.pm_prot = 0;
+       CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
+           tottimeout);
+       CLNT_DESTROY(client);
+       (void)close(socket);
+       return (rslt);
+}
diff --git a/TBBT/trace_play/rpc/pmap_clnt.h b/TBBT/trace_play/rpc/pmap_clnt.h
new file mode 100755 (executable)
index 0000000..9d7b74e
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * @(#)pmap_clnt.h     2.1     97/10/23
+ */
+/* @(#)pmap_clnt.h     2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * pmap_clnt.h
+ * Supplies C routines to get to portmap services.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+#ifndef _SRPC_PMAP_CLNT_H
+#define _SRPC_PMAP_CLNT_H
+
+
+/*
+ * Usage:
+ *     success = pmap_set(program, version, protocol, port);
+ *     success = pmap_unset(program, version);
+ *     port = pmap_getport(address, program, version, protocol);
+ *     head = pmap_getmaps(address);
+ *     clnt_stat = pmap_rmtcall(address, program, version, procedure,
+ *             xdrargs, argsp, xdrres, resp, tout, port_ptr)
+ *             (works for udp only.) 
+ *     clnt_stat = clnt_broadcast(program, version, procedure,
+ *             xdrargs, argsp, xdrres, resp, eachresult)
+ *             (like pmap_rmtcall, except the call is broadcasted to all
+ *             locally connected nets.  For each valid response received,
+ *             the procedure eachresult is called.  Its form is:
+ *     done = eachresult(resp, raddr)
+ *             bool_t done;
+ *             void * resp;
+ *             struct sockaddr_in raddr;
+ *             where resp points to the results of the call and raddr is the
+ *             address if the responder to the broadcast.
+ */
+
+typedef bool_t (*resultproc_t)();
+extern bool_t          pmap_set(uint32_t, uint32_t, int, uint16_t);
+extern bool_t          pmap_unset(uint32_t, uint32_t);
+extern struct pmaplist *pmap_getmaps(struct sockaddr_in *);
+extern enum clnt_stat  pmap_rmtcall(struct sockaddr_in *, uint32_t, uint32_t,
+                                       uint32_t, xdrproc_t, void *,
+                                       xdrproc_t, void *,
+                                       struct timeval, uint32_t *);
+extern enum clnt_stat  clnt_broadcast(uint32_t, uint32_t, uint32_t, xdrproc_t,
+                                       void *, xdrproc_t,
+                                       void *, resultproc_t);
+extern uint16_t                pmap_getport(struct sockaddr_in *, uint32_t, uint32_t,
+                                                               uint_t);
+#endif /* _SRPC_PMAP_CLNT_H */
diff --git a/TBBT/trace_play/rpc/pmap_getmaps.c b/TBBT/trace_play/rpc/pmap_getmaps.c
new file mode 100755 (executable)
index 0000000..ab1ce75
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef lint
+static char sfs_pmap_getmaps_id[] = "@(#)pmap_getmaps.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_getmaps.c  2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getmap.c
+ * Client interface to pmap rpc service.
+ * contains pmap_getmaps, which is only tcp service involved
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_prot.h"
+#include "rpc/pmap_clnt.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+
+#define NAMELEN 255
+#define MAX_BROADCAST_SIZE 1400
+
+
+/*
+ * Get a copy of the current port maps.
+ * Calls the pmap service remotely to do get the maps.
+ */
+struct pmaplist *
+pmap_getmaps(
+        struct sockaddr_in *address)
+{
+       struct pmaplist *head = (struct pmaplist *)NULL;
+       int socket = -1;
+       struct timeval minutetimeout;
+       register CLIENT *client;
+
+       minutetimeout.tv_sec = 60;
+       minutetimeout.tv_usec = 0;
+       address->sin_port = htons(PMAPPORT);
+       client = clnttcp_create(address, PMAPPROG,
+           PMAPVERS, &socket, 50, 500);
+       if (client != (CLIENT *)NULL) {
+               if (CLNT_CALL(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist,
+                   &head, minutetimeout) != RPC_SUCCESS) {
+                       clnt_perror(client, "pmap_getmaps rpc problem");
+               }
+               CLNT_DESTROY(client);
+       }
+       (void)close(socket);
+       address->sin_port = 0;
+       return (head);
+}
diff --git a/TBBT/trace_play/rpc/pmap_getport.c b/TBBT/trace_play/rpc/pmap_getport.c
new file mode 100755 (executable)
index 0000000..2457475
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)pmap_getport.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_getport.c  2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_prot.h"
+#include "rpc/pmap_clnt.h"
+#include "rpc/osdep.h"
+
+static struct timeval timeout = { 5, 0 };
+static struct timeval tottimeout = { 60, 0 };
+
+/*
+ * Find the mapped port for program,version.
+ * Calls the pmap service remotely to do the lookup.
+ * Returns 0 if no map exists.
+ */
+uint16_t
+pmap_getport(
+       struct sockaddr_in *address,
+       uint32_t program,
+       uint32_t version,
+       uint_t protocol)
+{
+       uint16_t port = 0;
+       int socket = -1;
+       register CLIENT *client;
+       struct pmap parms;
+
+       address->sin_port = htons(PMAPPORT);
+       client = clntudp_bufcreate(address, PMAPPROG,
+           PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+       if (client != (CLIENT *)NULL) {
+               parms.pm_prog = program;
+               parms.pm_vers = version;
+               parms.pm_prot = protocol;
+               parms.pm_port = 0;  /* not needed or used */
+               if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
+                   xdr_uint16_t, &port, tottimeout) != RPC_SUCCESS){
+                       rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+                       clnt_geterr(client, &rpc_createerr.cf_error);
+               } else if (port == 0) {
+                       rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+               }
+               CLNT_DESTROY(client);
+       }
+       (void)close(socket);
+       address->sin_port = 0;
+       return (port);
+}
diff --git a/TBBT/trace_play/rpc/pmap_prot.c b/TBBT/trace_play/rpc/pmap_prot.c
new file mode 100755 (executable)
index 0000000..242e846
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)pmap_prot.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_prot.c     2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/pmap_prot.h"
+
+
+bool_t
+xdr_pmap(
+       XDR *xdrs,
+       struct pmap *regs)
+{
+
+       if (xdr_uint32_t(xdrs, &regs->pm_prog) && 
+               xdr_uint32_t(xdrs, &regs->pm_vers) && 
+               xdr_uint32_t(xdrs, &regs->pm_prot))
+               return (xdr_uint32_t(xdrs, &regs->pm_port));
+       return (FALSE);
+}
diff --git a/TBBT/trace_play/rpc/pmap_prot.h b/TBBT/trace_play/rpc/pmap_prot.h
new file mode 100755 (executable)
index 0000000..adbd407
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * @(#)pmap_prot.h     2.1     97/10/23
+ */
+/* @(#)pmap_prot.h     2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * pmap_prot.h
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The following procedures are supported by the protocol:
+ *
+ * PMAPPROC_NULL() returns ()
+ *     takes nothing, returns nothing
+ *
+ * PMAPPROC_SET(struct pmap) returns (bool_t)
+ *     TRUE is success, FALSE is failure.  Registers the tuple
+ *     [prog, vers, prot, port].
+ *
+ * PMAPPROC_UNSET(struct pmap) returns (bool_t)
+ *     TRUE is success, FALSE is failure.  Un-registers pair
+ *     [prog, vers].  prot and port are ignored.
+ *
+ * PMAPPROC_GETPORT(struct pmap) returns (int32_t unsigned).
+ *     0 is failure.  Otherwise returns the port number where the pair
+ *     [prog, vers] is registered.  It may lie!
+ *
+ * PMAPPROC_DUMP() RETURNS (struct pmaplist *)
+ *
+ * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>)
+ *     RETURNS (port, string<>);
+ * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs);
+ *     Calls the procedure on the local machine.  If it is not registered,
+ *     this procedure is quite; ie it does not return error information!!!
+ *     This procedure only is supported on rpc/udp and calls via
+ *     rpc/udp.  This routine only passes null authentication parameters.
+ *     This file has no interface to xdr routines for PMAPPROC_CALLIT.
+ *
+ * The service supports remote procedure calls on udp/ip or tcp/ip socket 111.
+ */
+
+#define PMAPPORT               ((uint16_t)111)
+#define PMAPPROG               ((uint32_t)100000)
+#define PMAPVERS               ((uint32_t)2)
+#define PMAPVERS_PROTO         ((uint32_t)2)
+#define PMAPVERS_ORIG          ((uint32_t)1)
+#define PMAPPROC_NULL          ((uint32_t)0)
+#define PMAPPROC_SET           ((uint32_t)1)
+#define PMAPPROC_UNSET         ((uint32_t)2)
+#define PMAPPROC_GETPORT       ((uint32_t)3)
+#define PMAPPROC_DUMP          ((uint32_t)4)
+#define PMAPPROC_CALLIT                ((uint32_t)5)
+
+struct pmap {
+       uint32_t pm_prog;
+       uint32_t pm_vers;
+       uint32_t pm_prot;
+       uint32_t pm_port;
+};
+
+extern bool_t xdr_pmap();
+
+struct pmaplist {
+       struct pmap     pml_map;
+       struct pmaplist *pml_next;
+};
+
+extern bool_t xdr_pmaplist();
diff --git a/TBBT/trace_play/rpc/pmap_prot2.c b/TBBT/trace_play/rpc/pmap_prot2.c
new file mode 100755 (executable)
index 0000000..9cb238a
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)pmap_prot2.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_prot2.c    2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot2.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/pmap_prot.h"
+
+
+/* 
+ * What is going on with linked lists? (!)
+ * First recall the link list declaration from pmap_prot.h:
+ *
+ * struct pmaplist {
+ *     struct pmap pml_map;
+ *     struct pmaplist *pml_map;
+ * };
+ *
+ * Compare that declaration with a corresponding xdr declaration that 
+ * is (a) pointer-less, and (b) recursive:
+ *
+ * typedef union switch (bool_t) {
+ * 
+ *     case TRUE: struct {
+ *             struct pmap;
+ *             pmaplist_t foo;
+ *     };
+ *
+ *     case FALSE: struct {};
+ * } pmaplist_t;
+ *
+ * Notice that the xdr declaration has no nxt pointer while
+ * the C declaration has no bool_t variable.  The bool_t can be
+ * interpreted as ``more data follows me''; if FALSE then nothing
+ * follows this bool_t; if TRUE then the bool_t is followed by
+ * an actual struct pmap, and then (recursively) by the 
+ * xdr union, pamplist_t.  
+ *
+ * This could be implemented via the xdr_union primitive, though this
+ * would cause a one recursive call per element in the list.  Rather than do
+ * that we can ``unwind'' the recursion
+ * into a while loop and do the union arms in-place.
+ *
+ * The head of the list is what the C programmer wishes to past around
+ * the net, yet is the data that the pointer points to which is interesting;
+ * this sounds like a job for xdr_reference!
+ */
+bool_t
+xdr_pmaplist(
+       XDR *xdrs,
+       struct pmaplist **rp)
+{
+       /*
+        * more_elements is pre-computed in case the direction is
+        * XDR_ENCODE or XDR_FREE.  more_elements is overwritten by
+        * xdr_bool when the direction is XDR_DECODE.
+        */
+       bool_t more_elements;
+       register int freeing = (xdrs->x_op == XDR_FREE);
+       register struct pmaplist **next;
+
+       /* CONSTCOND */
+       while (TRUE) {
+               more_elements = (bool_t)(*rp != NULL);
+               if (! xdr_bool(xdrs, &more_elements))
+                       return (FALSE);
+               if (! more_elements)
+                       return (TRUE);  /* we are done */
+               /*
+                * the unfortunate side effect of non-recursion is that in
+                * the case of freeing we must remember the next object
+                * before we free the current object ...
+                */
+               if (freeing)
+                       next = &((*rp)->pml_next); 
+               if (! xdr_reference(xdrs, (void **)rp,
+                   (uint_t)sizeof(struct pmaplist), xdr_pmap))
+                       return (FALSE);
+               rp = (freeing) ? next : &((*rp)->pml_next);
+       }
+}
diff --git a/TBBT/trace_play/rpc/pmap_rmt.c b/TBBT/trace_play/rpc/pmap_rmt.c
new file mode 100755 (executable)
index 0000000..a834cfd
--- /dev/null
@@ -0,0 +1,419 @@
+#ifndef lint
+static char sfs_pmap_rmt_id[] = "@(#)pmap_rmt.c     2.1     97/10/23";
+#endif
+/* @(#)pmap_rmt.c      2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_rmt.c
+ * Client interface to pmap rpc service.
+ * remote call and broadcast service
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifndef FreeBSD
+#include <stropts.h>
+#endif /* ndef FreeBSD */
+#include <string.h>
+#include <errno.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_prot.h"
+#include "rpc/pmap_clnt.h"
+#include "rpc/pmap_rmt.h"
+#include "rpc/osdep.h"
+
+#define MAX_BROADCAST_SIZE 1400
+
+static struct timeval timeout = { 3, 0 };
+
+
+/*
+ * pmapper remote-call-service interface.
+ * This routine is used to call the pmapper remote call service
+ * which will look up a service program in the port maps, and then
+ * remotely call that routine with the given parameters.  This allows
+ * programs to do a lookup and call in one step.
+*/
+enum clnt_stat
+pmap_rmtcall(
+       struct sockaddr_in *addr,
+       uint32_t prog,
+       uint32_t vers,
+       uint32_t proc,
+       xdrproc_t xdrargs,
+       void *argsp,
+       xdrproc_t xdrres,
+       void *resp,
+       struct timeval tout,
+       uint32_t *port_ptr)
+{
+       int socket = -1;
+       register CLIENT *client;
+       struct rmtcallargs a;
+       struct rmtcallres r;
+       enum clnt_stat stat;
+
+       addr->sin_port = htons(PMAPPORT);
+       client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
+       if (client != (CLIENT *)NULL) {
+               a.prog = prog;
+               a.vers = vers;
+               a.proc = proc;
+               a.args_ptr = argsp;
+               a.xdr_args = xdrargs;
+               r.port_ptr = port_ptr;
+               r.results_ptr = resp;
+               r.xdr_results = xdrres;
+               stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
+                   xdr_rmtcallres, &r, tout);
+               CLNT_DESTROY(client);
+       } else {
+               stat = RPC_FAILED;
+       }
+       (void)close(socket);
+       addr->sin_port = 0;
+       return (stat);
+}
+
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rmtcall_args(
+       XDR *xdrs,
+       struct rmtcallargs *cap)
+{
+       uint_t lenposition, argposition, position;
+
+       if (xdr_uint32_t(xdrs, &(cap->prog)) &&
+           xdr_uint32_t(xdrs, &(cap->vers)) &&
+           xdr_uint32_t(xdrs, &(cap->proc))) {
+               lenposition = XDR_GETPOS(xdrs);
+               if (! xdr_uint32_t(xdrs, &(cap->arglen)))
+                   return (FALSE);
+               argposition = XDR_GETPOS(xdrs);
+               if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
+                   return (FALSE);
+               position = XDR_GETPOS(xdrs);
+               cap->arglen = (uint32_t)position - (uint32_t)argposition;
+               XDR_SETPOS(xdrs, lenposition);
+               if (! xdr_uint32_t(xdrs, &(cap->arglen)))
+                   return (FALSE);
+               XDR_SETPOS(xdrs, position);
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/*
+ * XDR remote call results
+ * written for XDR_DECODE direction only
+ */
+bool_t
+xdr_rmtcallres(
+       XDR *xdrs,
+       struct rmtcallres *crp)
+{
+       void *port_ptr;
+
+       port_ptr = (void *)crp->port_ptr;
+       if (xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
+           xdr_uint32_t) && xdr_uint32_t(xdrs, &crp->resultslen)) {
+               crp->port_ptr = (uint32_t *)port_ptr;
+               return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
+       }
+       return (FALSE);
+}
+
+
+/*
+ * The following is kludged-up support for simple rpc broadcasts.
+ * Someday a large, complicated system will replace these trivial 
+ * routines which only support udp/ip .
+ */
+
+static int
+getbroadcastnets(
+       struct in_addr *addrs,
+       int sock,
+       char *buf)
+{
+       struct ifconf ifc;
+        struct ifreq ifreq, *ifr;
+       struct sockaddr_in *sin;
+        int n, i;
+
+        ifc.ifc_len = UDPMSGSIZE;
+        ifc.ifc_buf = buf;
+        if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+                perror("broadcast: ioctl (get interface configuration)");
+                return (0);
+        }
+        ifr = ifc.ifc_req;
+        for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
+                ifreq = *ifr;
+                if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                        perror("broadcast: ioctl (get interface flags)");
+                        continue;
+                }
+                if ((ifreq.ifr_flags & IFF_BROADCAST) &&
+                   (ifreq.ifr_flags & IFF_UP) &&
+                   ifr->ifr_addr.sa_family == AF_INET) {
+                       sin = (struct sockaddr_in *)&ifr->ifr_addr;
+#ifdef SIOCGIFBRDADDR   /* 4.3BSD */
+                       if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+                               addrs[i++] = inet_makeaddr((int)inet_netof
+                           (sin->sin_addr), INADDR_ANY);
+                       } else {
+                               addrs[i++] = ((struct sockaddr_in*)
+                                 &ifreq.ifr_addr)->sin_addr;
+                       }
+#else /* 4.2 BSD */
+                       addrs[i++] = inet_makeaddr(inet_netof
+                         (sin->sin_addr.s_addr), INADDR_ANY);
+#endif
+               }
+       }
+       return (i);
+}
+
+enum clnt_stat 
+clnt_broadcast(
+       uint32_t        prog,           /* program number */
+       uint32_t        vers,           /* version number */
+       uint32_t        proc,           /* procedure number */
+       xdrproc_t       xargs,          /* xdr routine for args */
+       void *          argsp,          /* pointer to args */
+       xdrproc_t       xresults,       /* xdr routine for results */
+       void *          resultsp,       /* pointer to results */
+       resultproc_t    eachresult)     /* call with each result obtained */
+{
+       enum clnt_stat stat;
+       AUTH *unix_auth = authunix_create_default();
+       XDR xdr_stream;
+       register XDR *xdrs = &xdr_stream;
+       int outlen, inlen, nets;
+#if defined(AIX)
+       size_t fromlen;
+#else
+       int fromlen;
+#endif /* AIX */
+       register int sock;
+       int on = 1;
+#ifdef FD_SETSIZE
+       fd_set mask;
+       fd_set readfds;
+#else
+       int readfds;
+       register int mask;
+#endif /* def FD_SETSIZE */
+       register int i;
+       bool_t done = FALSE;
+       register uint32_t xid;
+       uint32_t port;
+       struct in_addr addrs[20];
+       struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
+       struct rmtcallargs a;
+       struct rmtcallres r;
+       struct rpc_msg msg;
+       struct timeval t; 
+       char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
+
+       /*
+        * initialization: create a socket, a broadcast address, and
+        * preserialize the arguments into a send buffer.
+        */
+       if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+               perror("Cannot create socket for broadcast rpc");
+               stat = RPC_CANTSEND;
+               goto done_broad;
+       }
+#ifdef SO_BROADCAST
+       if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof (on)) < 0) {
+               perror("Cannot set socket option SO_BROADCAST");
+               stat = RPC_CANTSEND;
+               goto done_broad;
+       }
+#endif /* def SO_BROADCAST */
+#ifdef FD_SETSIZE
+       FD_ZERO(&mask);
+       FD_SET(sock, &mask);
+#else
+       mask = (1 << sock);
+#endif /* def FD_SETSIZE */
+       nets = getbroadcastnets(addrs, sock, inbuf);
+       memset((char *)&baddr, '\0', sizeof (baddr));
+       baddr.sin_family = AF_INET;
+       baddr.sin_port = htons(PMAPPORT);
+       baddr.sin_addr.s_addr = htonl(INADDR_ANY);
+/*     baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
+       (void)gettimeofday(&t, (struct timezone *)0);
+       msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
+       t.tv_usec = 0;
+       msg.rm_direction = CALL;
+       msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       msg.rm_call.cb_prog = PMAPPROG;
+       msg.rm_call.cb_vers = PMAPVERS;
+       msg.rm_call.cb_proc = PMAPPROC_CALLIT;
+       msg.rm_call.cb_cred = unix_auth->ah_cred;
+       msg.rm_call.cb_verf = unix_auth->ah_verf;
+       a.prog = prog;
+       a.vers = vers;
+       a.proc = proc;
+       a.xdr_args = xargs;
+       a.args_ptr = argsp;
+       r.port_ptr = &port;
+       r.xdr_results = xresults;
+       r.results_ptr = resultsp;
+       xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
+       if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
+               stat = RPC_CANTENCODEARGS;
+               goto done_broad;
+       }
+       outlen = (int)xdr_getpos(xdrs);
+       xdr_destroy(xdrs);
+       /*
+        * Basic loop: broadcast a packet and wait a while for response(s).
+        * The response timeout grows larger per iteration.
+        */
+       for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
+               for (i = 0; i < nets; i++) {
+                       baddr.sin_addr = addrs[i];
+                       if (sendto(sock, outbuf, outlen, 0,
+                               (struct sockaddr *)&baddr,
+                               sizeof (struct sockaddr)) != outlen) {
+                               perror("Cannot send broadcast packet");
+                               stat = RPC_CANTSEND;
+                               goto done_broad;
+                       }
+               }
+               if (eachresult == NULL) {
+                       stat = RPC_SUCCESS;
+                       goto done_broad;
+               }
+       recv_again:
+               msg.acpted_rply.ar_verf = _null_auth;
+               msg.acpted_rply.ar_results.where = (void *)&r;
+                msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
+               readfds = mask;
+               switch (select(_rpc_dtablesize(), &readfds, NULL, 
+                              NULL, &t)) {
+
+               case 0:  /* timed out */
+                       stat = RPC_TIMEDOUT;
+                       continue;
+
+               case -1:  /* some kind of error */
+                       if (errno == EINTR)
+                               goto recv_again;
+                       perror("Broadcast select problem");
+                       stat = RPC_CANTRECV;
+                       goto done_broad;
+
+               }  /* end of select results switch */
+       try_again:
+               fromlen = sizeof(struct sockaddr);
+               inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
+                       (struct sockaddr *)&raddr, &fromlen);
+               if (inlen < 0) {
+                       if (errno == EINTR)
+                               goto try_again;
+                       perror("Cannot receive reply to broadcast");
+                       stat = RPC_CANTRECV;
+                       goto done_broad;
+               }
+               if (inlen < sizeof(uint32_t))
+                       goto recv_again;
+               /*
+                * see if reply transaction id matches sent id.
+                * If so, decode the results.
+                */
+               xdrmem_create(xdrs, inbuf, (uint_t)inlen, XDR_DECODE);
+               if (xdr_replymsg(xdrs, &msg)) {
+                       if ((msg.rm_xid == xid) &&
+                               (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+                               (msg.acpted_rply.ar_stat == SUCCESS)) {
+                               raddr.sin_port = htons((uint16_t)port);
+                               done = (*eachresult)(resultsp, &raddr);
+                       }
+                       /* otherwise, we just ignore the errors ... */
+               } else {
+#ifdef notdef
+                       /* some kind of deserialization problem ... */
+                       if (msg.rm_xid == xid)
+                               fprintf(stderr, "Broadcast deserialization problem");
+                       /* otherwise, just random garbage */
+#endif
+               }
+               xdrs->x_op = XDR_FREE;
+               msg.acpted_rply.ar_results.proc = xdr_void;
+               (void)xdr_replymsg(xdrs, &msg);
+               (void)(*xresults)(xdrs, resultsp);
+               xdr_destroy(xdrs);
+               if (done) {
+                       stat = RPC_SUCCESS;
+                       goto done_broad;
+               } else {
+                       goto recv_again;
+               }
+       }
+done_broad:
+       (void)close(sock);
+       AUTH_DESTROY(unix_auth);
+       return (stat);
+}
+
diff --git a/TBBT/trace_play/rpc/pmap_rmt.h b/TBBT/trace_play/rpc/pmap_rmt.h
new file mode 100755 (executable)
index 0000000..40a770a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * @(#)pmap_rmt.h     2.1     97/10/23
+ */
+/* @(#)pmap_rmt.h      2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Structures and XDR routines for parameters to and replies from
+ * the portmapper remote-call-service.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+struct rmtcallargs {
+       uint32_t prog, vers, proc, arglen;
+       void *args_ptr;
+       xdrproc_t xdr_args;
+};
+
+bool_t xdr_rmtcall_args();
+
+struct rmtcallres {
+       uint32_t *port_ptr;
+       uint32_t resultslen;
+       caddr_t results_ptr;
+       xdrproc_t xdr_results;
+};
+
+bool_t xdr_rmtcallres();
diff --git a/TBBT/trace_play/rpc/rpc.h b/TBBT/trace_play/rpc/rpc.h
new file mode 100755 (executable)
index 0000000..43935d6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * @(#)rpc.h     2.1     97/10/23
+ */
+
+/* @(#)rpc.h   2.4 89/07/11 4.0 RPCSRC; from 1.9 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * rpc.h, Just includes the billions of rpc header files necessary to
+ * do remote procedure calling.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef __RPC_HEADER__
+#define __RPC_HEADER__
+
+#include "rpc/types.h"         /* some typedefs */
+
+#include "rpc/osdep.h"
+
+/* external data representation interfaces */
+#include "rpc/xdr.h"           /* generic (de)serializer */
+
+/* Client side only authentication */
+#include "rpc/auth.h"          /* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include "rpc/clnt.h"          /* generic rpc stuff */
+
+#include "rpc/pmap_clnt.h"
+
+/* semi-private protocol headers */
+#include "rpc/rpc_msg.h"       /* protocol for rpc messages */
+#include "rpc/auth_unix.h"     /* protocol for unix style cred */
+/*
+ *  Uncomment-out the next line if you are building the rpc library with    
+ *  DES Authentication (see the README file in the secure_rpc/ directory).
+ */
+#ifdef notdef
+#include "rpc/auth_des.h"      /* protocol for des style cred */
+#endif
+
+/* Server side only remote procedure callee */
+#include "rpc/svc.h"           /* service manager and multiplexer */
+#include "rpc/svc_auth.h"      /* service side authenticator */
+
+#endif /* ndef __RPC_HEADER__ */
diff --git a/TBBT/trace_play/rpc/rpc_callmsg.c b/TBBT/trace_play/rpc/rpc_callmsg.c
new file mode 100755 (executable)
index 0000000..e7bfdc8
--- /dev/null
@@ -0,0 +1,214 @@
+#ifndef lint
+static char sfs_rpc_callmsg_c_id[] = "@(#)rpc_callmsg.c     2.1     97/10/23";
+#endif
+/* @(#)rpc_callmsg.c   2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_callmsg.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "rpc/rpc.h"
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg(
+       XDR *xdrs,
+       struct rpc_msg *cmsg)
+{
+       int32_t *buf;
+       struct opaque_auth *oa;
+
+       if (xdrs->x_op == XDR_ENCODE) {
+               if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
+                       return (FALSE);
+               }
+               if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
+                       return (FALSE);
+               }
+               buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
+                       + RNDUP(cmsg->rm_call.cb_cred.oa_length)
+                       + 2 * BYTES_PER_XDR_UNIT
+                       + RNDUP(cmsg->rm_call.cb_verf.oa_length));
+               if (buf != NULL) {
+                       IXDR_PUT_LONG(buf, cmsg->rm_xid);
+                       IXDR_PUT_ENUM(buf, cmsg->rm_direction);
+                       if (cmsg->rm_direction != CALL) {
+                               return (FALSE);
+                       }
+                       IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers);
+                       if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+                               return (FALSE);
+                       }
+                       IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog);
+                       IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers);
+                       IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc);
+                       oa = &cmsg->rm_call.cb_cred;
+                       IXDR_PUT_ENUM(buf, oa->oa_flavor);
+                       IXDR_PUT_LONG(buf, oa->oa_length);
+                       if (oa->oa_length) {
+                               memmove((caddr_t)buf, oa->oa_base, oa->oa_length);
+                               buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+                       }
+                       oa = &cmsg->rm_call.cb_verf;
+                       IXDR_PUT_ENUM(buf, oa->oa_flavor);
+                       IXDR_PUT_LONG(buf, oa->oa_length);
+                       if (oa->oa_length) {
+                               memmove((caddr_t)buf, oa->oa_base, oa->oa_length);
+                               /* no real need....
+                               buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+                               */
+                       }
+                       return (TRUE);
+               }
+       }
+       if (xdrs->x_op == XDR_DECODE) {
+               buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
+               if (buf != NULL) {
+                       cmsg->rm_xid = IXDR_GET_LONG(buf);
+                       cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
+                       if (cmsg->rm_direction != CALL) {
+                               return (FALSE);
+                       }
+                       cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf);
+                       if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+                               return (FALSE);
+                       }
+                       cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf);
+                       cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf);
+                       cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf);
+                       oa = &cmsg->rm_call.cb_cred;
+                       oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+                       oa->oa_length = IXDR_GET_LONG(buf);
+                       if (oa->oa_length) {
+                               if (oa->oa_length > MAX_AUTH_BYTES) {
+                                       return (FALSE);
+                               }
+                               if (oa->oa_base == NULL) {
+                                       oa->oa_base = (caddr_t)
+                                               mem_alloc(oa->oa_length);
+                               }
+                               buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+                               if (buf == NULL) {
+                                       if (xdr_opaque(xdrs, oa->oa_base,
+                                           oa->oa_length) == FALSE) {
+                                               return (FALSE);
+                                       }
+                               } else {
+                                       memmove(oa->oa_base, (caddr_t)buf,
+                                           oa->oa_length);
+                                       /* no real need....
+                                       buf += RNDUP(oa->oa_length) /
+                                               sizeof (int32_t);
+                                       */
+                               }
+                       }
+                       oa = &cmsg->rm_call.cb_verf;
+                       buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
+                       if (buf == NULL) {
+                               if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
+                                   xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
+                                       return (FALSE);
+                               }
+                       } else {
+                               oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+                               oa->oa_length = IXDR_GET_LONG(buf);
+                       }
+                       if (oa->oa_length) {
+                               if (oa->oa_length > MAX_AUTH_BYTES) {
+                                       return (FALSE);
+                               }
+                               if (oa->oa_base == NULL) {
+                                       oa->oa_base = (caddr_t)
+                                               mem_alloc(oa->oa_length);
+                               }
+                               buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+                               if (buf == NULL) {
+                                       if (xdr_opaque(xdrs, oa->oa_base,
+                                           oa->oa_length) == FALSE) {
+                                               return (FALSE);
+                                       }
+                               } else {
+                                       memmove(oa->oa_base, (caddr_t)buf,
+                                           oa->oa_length);
+                                       /* no real need...
+                                       buf += RNDUP(oa->oa_length) /
+                                               sizeof (int32_t);
+                                       */
+                               }
+                       }
+                       return (TRUE);
+               }
+       }
+       if (
+           xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
+           xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
+           (cmsg->rm_direction == CALL) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+           (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_proc)) &&
+           xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
+           return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
+       return (FALSE);
+}
+
diff --git a/TBBT/trace_play/rpc/rpc_commondata.c b/TBBT/trace_play/rpc/rpc_commondata.c
new file mode 100755 (executable)
index 0000000..c2df017
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef lint
+static char sfs_rpc_commondata_id[] = "@(#)rpc_commondata.c     2.1     97/10/23";
+#endif
+/* @(#)rpc_commondata.c        2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#include "rpc/rpc.h"
+/*
+ * This file should only contain common data (global data) that is exported
+ * by public interfaces 
+ */
+struct opaque_auth _null_auth;
+#ifdef FD_SETSIZE
+fd_set svc_fdset;
+#else
+int svc_fds;
+#endif /* def FD_SETSIZE */
+struct rpc_createerr rpc_createerr;
diff --git a/TBBT/trace_play/rpc/rpc_dtablesize.c b/TBBT/trace_play/rpc/rpc_dtablesize.c
new file mode 100755 (executable)
index 0000000..8c1d9f9
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)rpc_dtablesize.c     2.1     97/10/23";
+#endif
+/* @(#)rpc_dtablesize.c        2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";
+#endif
+
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+
+#if !(defined(USE_GETDTABLESIZE) || defined(USE_GETRLIMIT) || defined(USE_NOFILE))
+#define USE_GETDTABLESIZE
+#endif
+
+#ifdef USE_GETDTABLESIZE
+#include <unistd.h>
+
+int
+_rpc_dtablesize(void)
+{
+       static int size = 0;
+       
+       if (size == 0) {
+               size = getdtablesize();
+#ifdef FD_SETSIZE
+               /*
+                * FreeBSD select() produces a segmentation violation if
+                * the argument is larger than FD_SETSIZE.
+                */
+               if (size > FD_SETSIZE) {
+                       size = FD_SETSIZE;
+               }
+#endif /* def FD_SETSIZE */
+       }
+       return (size);
+}
+#endif
+
+#ifdef USE_GETRLIMIT
+#include <sys/resource.h>
+
+int
+_rpc_dtablesize(void)
+{
+       static int size = 0;
+       struct rlimit rlimit;
+
+       if (size == 0) {
+               (void)getrlimit(RLIMIT_NOFILE, &rlimit);
+               size = (int) rlimit.rlim_cur;
+       }
+       return (size);
+}
+#endif
+
+#ifdef USE_NOFILE
+#include <sys/param.h>
+
+int
+_rpc_dtablesize(void)
+{
+       return (NOFILE);
+}
+#endif
diff --git a/TBBT/trace_play/rpc/rpc_msg.h b/TBBT/trace_play/rpc/rpc_msg.h
new file mode 100755 (executable)
index 0000000..fde7b93
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * @(#)rpc_msg.h     2.1     97/10/23
+ */
+/* @(#)rpc_msg.h       2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)rpc_msg.h 1.7 86/07/16 SMI      */
+
+/*
+ * rpc_msg.h
+ * rpc message definition
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef __RPC_MSG_H
+#define __RPC_MSG_H
+
+#define RPC_MSG_VERSION                ((uint32_t) 2)
+#define RPC_SERVICE_PORT       ((uint16_t) 2048)
+
+/*
+ * Bottom up definition of an rpc message.
+ * NOTE: call and reply use the same overall stuct but
+ * different parts of unions within it.
+ */
+
+enum msg_type {
+       CALL=0,
+       REPLY=1
+};
+
+enum reply_stat {
+       MSG_ACCEPTED=0,
+       MSG_DENIED=1
+};
+
+enum accept_stat {
+       SUCCESS=0,
+       PROG_UNAVAIL=1,
+       PROG_MISMATCH=2,
+       PROC_UNAVAIL=3,
+       GARBAGE_ARGS=4,
+       SYSTEM_ERR=5
+};
+
+enum reject_stat {
+       RPC_MISMATCH=0,
+       AUTH_ERROR=1
+};
+
+/*
+ * Reply part of an rpc exchange
+ */
+
+/*
+ * Reply to an rpc request that was accepted by the server.
+ * Note: there could be an error even though the request was
+ * accepted.
+ */
+struct accepted_reply {
+       struct opaque_auth      ar_verf;
+       enum accept_stat        ar_stat;
+       union {
+               struct {
+                       uint32_t        low;
+                       uint32_t        high;
+               } AR_versions;
+               struct {
+                       void *  where;
+                       xdrproc_t proc;
+               } AR_results;
+               /* and many other null cases */
+       } ru;
+#define        ar_results      ru.AR_results
+#define        ar_vers         ru.AR_versions
+};
+
+/*
+ * Reply to an rpc request that was rejected by the server.
+ */
+struct rejected_reply {
+       enum reject_stat rj_stat;
+       union {
+               struct {
+                       uint32_t low;
+                       uint32_t high;
+               } RJ_versions;
+               enum auth_stat RJ_why;  /* why authentication did not work */
+       } ru;
+#define        rj_vers ru.RJ_versions
+#define        rj_why  ru.RJ_why
+};
+
+/*
+ * Body of a reply to an rpc request.
+ */
+struct reply_body {
+       enum reply_stat rp_stat;
+       union {
+               struct accepted_reply RP_ar;
+               struct rejected_reply RP_dr;
+       } ru;
+#define        rp_acpt ru.RP_ar
+#define        rp_rjct ru.RP_dr
+};
+
+/*
+ * Body of an rpc request call.
+ */
+struct call_body {
+       uint32_t cb_rpcvers;    /* must be equal to two */
+       uint32_t cb_prog;
+       uint32_t cb_vers;
+       uint32_t cb_proc;
+       struct opaque_auth cb_cred;
+       struct opaque_auth cb_verf; /* protocol specific - provided by client */
+};
+
+/*
+ * The rpc message
+ */
+struct rpc_msg {
+       uint32_t                rm_xid;
+       enum msg_type           rm_direction;
+       union {
+               struct call_body RM_cmb;
+               struct reply_body RM_rmb;
+       } ru;
+#define        rm_call         ru.RM_cmb
+#define        rm_reply        ru.RM_rmb
+};
+#define        acpted_rply     ru.RM_rmb.ru.RP_ar
+#define        rjcted_rply     ru.RM_rmb.ru.RP_dr
+
+
+/*
+ * XDR routine to handle a rpc message.
+ * xdr_callmsg(xdrs, cmsg)
+ *     XDR *xdrs;
+ *     struct rpc_msg *cmsg;
+ */
+extern bool_t  xdr_callmsg(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to pre-serialize the static part of a rpc message.
+ * xdr_callhdr(xdrs, cmsg)
+ *     XDR *xdrs;
+ *     struct rpc_msg *cmsg;
+ */
+extern bool_t  xdr_callhdr(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to handle a rpc reply.
+ * xdr_replymsg(xdrs, rmsg)
+ *     XDR *xdrs;
+ *     struct rpc_msg *rmsg;
+ */
+extern bool_t  xdr_replymsg(XDR *, struct rpc_msg *);
+
+/*
+ * Fills in the error part of a reply message.
+ * _seterr_reply(msg, error)
+ *     struct rpc_msg *msg;
+ *     struct rpc_err *error;
+ */
+extern void    _seterr_reply(struct rpc_msg *, struct rpc_err *);
+
+extern int     _rpc_dtablesize(void);
+extern bool_t  xdr_opaque_auth(XDR *, struct opaque_auth *);
+#endif /* __RPC_MSG_H */
diff --git a/TBBT/trace_play/rpc/rpc_prot.c b/TBBT/trace_play/rpc/rpc_prot.c
new file mode 100755 (executable)
index 0000000..623ee7a
--- /dev/null
@@ -0,0 +1,307 @@
+#ifndef lint
+static char sfs_rpc_prot_id[] = "@(#)rpc_prot.c     2.1     97/10/23";
+#endif
+/* @(#)rpc_prot.c      2.3 88/08/07 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_prot.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements the rpc message definition,
+ * its serializer and some common rpc utility routines.
+ * The routines are meant for various implementations of rpc -
+ * they are NOT for the rpc client or rpc service implementations!
+ * Because authentication stuff is easy and is part of rpc, the opaque
+ * routines are also in this program.
+ */
+
+#include "rpc/rpc.h"
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+struct opaque_auth _null_auth;
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth(
+       XDR *xdrs,
+       struct opaque_auth *ap)
+{
+
+       if (xdr_enum(xdrs, &(ap->oa_flavor)))
+               return (xdr_bytes(xdrs, (void *)&ap->oa_base,
+                       &ap->oa_length, MAX_AUTH_BYTES));
+       return (FALSE);
+}
+
+/*
+ * XDR a DES block
+ */
+bool_t
+xdr_des_block(
+       XDR *xdrs,
+       des_block *blkp)
+{
+       return (xdr_opaque(xdrs, (void *)blkp, sizeof(des_block)));
+}
+
+/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
+
+/*
+ * XDR the MSG_ACCEPTED part of a reply message union
+ */
+bool_t 
+xdr_accepted_reply(
+       XDR *xdrs,   
+       struct accepted_reply *ar)
+{
+
+       /* personalized union, rather than calling xdr_union */
+       if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
+               return (FALSE);
+       if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat)))
+               return (FALSE);
+       switch (ar->ar_stat) {
+
+       case SUCCESS:
+               return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
+
+       case PROG_MISMATCH:
+               if (! xdr_uint32_t(xdrs, &(ar->ar_vers.low)))
+                       return (FALSE);
+               return (xdr_uint32_t(xdrs, &(ar->ar_vers.high)));
+       }
+       return (TRUE);  /* TRUE => open ended set of problems */
+}
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t 
+xdr_rejected_reply(
+       XDR *xdrs,
+       struct rejected_reply *rr)
+{
+
+       /* personalized union, rather than calling xdr_union */
+       if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat)))
+               return (FALSE);
+       switch (rr->rj_stat) {
+
+       case RPC_MISMATCH:
+               if (! xdr_uint32_t(xdrs, &(rr->rj_vers.low)))
+                       return (FALSE);
+               return (xdr_uint32_t(xdrs, &(rr->rj_vers.high)));
+
+       case AUTH_ERROR:
+               return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why)));
+       }
+       return (FALSE);
+}
+
+static struct xdr_discrim reply_dscrm[3] = {
+       { (int)MSG_ACCEPTED, xdr_accepted_reply },
+       { (int)MSG_DENIED, xdr_rejected_reply },
+       { __dontcare__, NULL_xdrproc_t } };
+
+/*
+ * XDR a reply message
+ */
+bool_t
+xdr_replymsg(
+       XDR *xdrs,
+       struct rpc_msg *rmsg)
+{
+       if (
+           xdr_uint32_t(xdrs, &(rmsg->rm_xid)) && 
+           xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) &&
+           (rmsg->rm_direction == REPLY) )
+               return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat),
+                  (void *)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t));
+       return (FALSE);
+}
+
+
+/*
+ * Serializes the "static part" of a call message header.
+ * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
+ * The rm_xid is not really static, but the user can easily munge on the fly.
+ */
+bool_t
+xdr_callhdr(
+       XDR *xdrs,
+       struct rpc_msg *cmsg)
+{
+
+       cmsg->rm_direction = CALL;
+       cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       if (
+           (xdrs->x_op == XDR_ENCODE) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
+           xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+           xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) )
+           return (xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)));
+       return (FALSE);
+}
+
+/* ************************** Client utility routine ************* */
+
+static void
+accepted(
+       enum accept_stat acpt_stat,
+       struct rpc_err *error)
+{
+
+       switch (acpt_stat) {
+
+       case PROG_UNAVAIL:
+               error->re_status = RPC_PROGUNAVAIL;
+               return;
+
+       case PROG_MISMATCH:
+               error->re_status = RPC_PROGVERSMISMATCH;
+               return;
+
+       case PROC_UNAVAIL:
+               error->re_status = RPC_PROCUNAVAIL;
+               return;
+
+       case GARBAGE_ARGS:
+               error->re_status = RPC_CANTDECODEARGS;
+               return;
+
+       case SYSTEM_ERR:
+               error->re_status = RPC_SYSTEMERROR;
+               return;
+
+       case SUCCESS:
+               error->re_status = RPC_SUCCESS;
+               return;
+       }
+       /* something's wrong, but we don't know what ... */
+       error->re_status = RPC_FAILED;
+       error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
+       error->re_lb.s2 = (int32_t)acpt_stat;
+}
+
+static void 
+rejected(
+       enum reject_stat rjct_stat,
+       struct rpc_err *error)
+{
+
+       if ((int)rjct_stat == (int)RPC_VERSMISMATCH) {
+               error->re_status = RPC_VERSMISMATCH;
+               return;
+       }
+       if (rjct_stat == AUTH_ERROR) {
+               error->re_status = RPC_AUTHERROR;
+               return;
+       }
+
+       /* something's wrong, but we don't know what ... */
+       error->re_status = RPC_FAILED;
+       error->re_lb.s1 = (int32_t)MSG_DENIED;
+       error->re_lb.s2 = (int32_t)rjct_stat;
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+void
+_seterr_reply(
+       struct rpc_msg *msg,
+       struct rpc_err *error)
+{
+
+       /* optimized for normal, SUCCESSful case */
+       switch (msg->rm_reply.rp_stat) {
+
+       case MSG_ACCEPTED:
+               if (msg->acpted_rply.ar_stat == SUCCESS) {
+                       error->re_status = RPC_SUCCESS;
+                       return;
+               };
+               accepted(msg->acpted_rply.ar_stat, error);
+               break;
+
+       case MSG_DENIED:
+               rejected(msg->rjcted_rply.rj_stat, error);
+               break;
+
+       default:
+               error->re_status = RPC_FAILED;
+               error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
+               break;
+       }
+       switch (error->re_status) {
+
+       case RPC_VERSMISMATCH:
+               error->re_vers.low = msg->rjcted_rply.rj_vers.low;
+               error->re_vers.high = msg->rjcted_rply.rj_vers.high;
+               break;
+
+       case RPC_AUTHERROR:
+               error->re_why = msg->rjcted_rply.rj_why;
+               break;
+
+       case RPC_PROGVERSMISMATCH:
+               error->re_vers.low = msg->acpted_rply.ar_vers.low;
+               error->re_vers.high = msg->acpted_rply.ar_vers.high;
+               break;
+       }
+}
diff --git a/TBBT/trace_play/rpc/sfs_ctcp.c b/TBBT/trace_play/rpc/sfs_ctcp.c
new file mode 100755 (executable)
index 0000000..d6a19f0
--- /dev/null
@@ -0,0 +1,727 @@
+#ifndef lint
+static char sfs_ctcp_id[] = "@(#)sfs_ctcp.c     2.1     97/10/23";
+#endif
+/* @(#)clnt_tcp.c      2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+#endif
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer.  The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message.  Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+#include <errno.h>
+#include "rpc/pmap_clnt.h"
+
+#define MCALL_MSG_SIZE 24
+
+struct ct_data {
+       int             ct_sock;
+       bool_t          ct_closeit;
+       struct timeval  ct_wait;
+       struct sockaddr_in ct_addr; 
+       struct sockaddr_in ct_oaddr; 
+       struct rpc_err  ct_error;
+       char            ct_mcall[MCALL_MSG_SIZE];       /* marshalled callmsg */
+       uint_t          ct_mpos;                        /* pos after marshal */
+       XDR             ct_xdrs;
+       int             ct_first;
+       uint32_t        ct_prog;
+       uint32_t        ct_vers;
+       uint_t          ct_sendsz;
+       uint_t          ct_recvsz;
+};
+
+static int     readtcp(struct ct_data *, char *, int);
+static int     writetcp(struct ct_data *ct, char * buf, int len);
+
+static enum clnt_stat  sfs_ctcp_call(CLIENT *, uint32_t, xdrproc_t, void *,
+                                       xdrproc_t, void *, struct timeval);
+static void            sfs_ctcp_abort(CLIENT *);
+static void            sfs_ctcp_geterr(CLIENT *, struct rpc_err *);
+static bool_t          sfs_ctcp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t          sfs_ctcp_control(CLIENT *, uint_t, void *);
+static void            sfs_ctcp_destroy(CLIENT *);
+static bool_t          sfs_ctcp_getreply(CLIENT *, xdrproc_t, void *,
+                               int, uint32_t *, uint32_t *, struct timeval *);
+static int             sfs_ctcp_poll(CLIENT *, uint32_t);
+
+static struct clnt_ops tcp_ops = {
+       sfs_ctcp_call,
+       sfs_ctcp_abort,
+       sfs_ctcp_geterr,
+       sfs_ctcp_freeres,
+       sfs_ctcp_destroy,
+       sfs_ctcp_control,
+       sfs_ctcp_getreply,
+       sfs_ctcp_poll
+};
+
+static int
+sfs_ctcp_make_conn(
+       struct ct_data *ct,
+       struct sockaddr_in *raddr,
+       int *sockp)
+{
+       int i;
+        int min_buf_sz;
+        int new_buf_sz;
+        int type;
+        int error;
+       int setopt = 1;
+#if defined(UNIXWARE) || defined(AIX)
+        size_t optlen;
+#else
+        int optlen;
+#endif
+
+       if (ct->ct_first == 0)
+               ct->ct_first++;
+
+#ifdef DEBUG
+       if (ct->ct_first)
+               (void) fprintf(stderr, "Re-establishing connection.\n");
+#endif
+
+       /*
+        * If no port number given ask the pmap for one
+        */
+       if (raddr->sin_port == 0) {
+               uint16_t port;
+               if ((port = pmap_getport(raddr, ct->ct_prog, ct->ct_vers,
+                                                       IPPROTO_TCP)) == 0) {
+                       return (-1);
+               }
+               raddr->sin_port = htons(port);
+       }
+
+       /*
+        * If no socket given, open one
+        */
+       if (*sockp >= 0) {
+               ct->ct_closeit = FALSE;
+               return (*sockp);
+       }
+
+       ct->ct_closeit = TRUE;
+
+       *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       (void)bindresvport(*sockp, (struct sockaddr_in *)0);
+       if ((*sockp < 0)
+           || (connect(*sockp, (struct sockaddr *)raddr,
+           sizeof(struct sockaddr_in)) < 0)) {
+               return (-1);
+       }
+
+        /*
+         * Need to try to size the socket buffers based on the number of
+         * outstanding requests desired.  NFS reads and writes can do as
+         * much as 8K per request which can quickly run us out of space
+         * on the socket buffer queue.  Use the maximum number of bio style
+         * requests * NFS_MAXDATA plus a pad as a starting point for desired
+         * socket buffer size and then back off by NFS_MAXDATA until the buffer
+         * sizes are successfully set.  Note, the algorithm never sets the
+         * buffer size to less than the OS default.
+         */
+        type = SO_SNDBUF;
+        for (i = 0; i < 2; i++) {
+                optlen = sizeof(min_buf_sz);
+#ifdef UNIXWARE
+                if (getsockopt(*sockp, SOL_SOCKET, type,
+                                (void *)&min_buf_sz, &optlen) < 0) {
+                        /* guess the default */
+                        min_buf_sz = 18 * 1024;
+                }
+#else
+                if (getsockopt(*sockp, SOL_SOCKET, type,
+                                (char *)&min_buf_sz, &optlen) < 0) {
+                        /* guess the default */
+                        min_buf_sz = 18 * 1024;
+                }
+#endif
+
+                new_buf_sz = 512 * 1024;
+                if (new_buf_sz > min_buf_sz) {
+                        do {
+                                error = setsockopt(*sockp, SOL_SOCKET,
+                                                type, (char *)&new_buf_sz,
+                                                sizeof(int));
+                                new_buf_sz -= (8 * 1024);
+                        } while (error != 0 && new_buf_sz > min_buf_sz);
+                }
+
+                type = SO_RCVBUF;
+        }
+
+#ifdef TCP_NODELAY
+       setsockopt(*sockp, IPPROTO_TCP, TCP_NODELAY, (char *) &setopt,
+               sizeof(setopt));
+#endif /* TCP_NODELAY */
+
+       return (*sockp);
+}
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr.  If *sockp non-negative then
+ * raddr is ignored.  The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+sfs_ctcp_create(
+       struct sockaddr_in *raddr,
+       uint32_t prog,
+       uint32_t vers,
+       int *sockp,
+       uint_t sendsz,
+       uint_t recvsz)
+{
+       CLIENT *h;
+       struct ct_data *ct;
+       struct timeval now;
+       struct rpc_msg call_msg;
+
+       h  = (CLIENT *)mem_alloc(sizeof(CLIENT));
+       if (h == NULL) {
+               (void)fprintf(stderr, "clnttcp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       ct = (struct ct_data *)mem_alloc(sizeof(struct ct_data));
+       if (ct == NULL) {
+               (void)fprintf(stderr, "clnttcp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       (void) memset(ct, '\0', sizeof (struct ct_data));
+
+       ct->ct_oaddr = *raddr;
+       ct->ct_prog = prog;
+       ct->ct_vers = vers;
+
+       if (sfs_ctcp_make_conn(ct, raddr, sockp) < 0) {
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               (void)close(*sockp);
+               goto fooy;
+       }
+
+       /*
+        * Set up private data struct
+        */
+       ct->ct_sock = *sockp;
+       ct->ct_wait.tv_sec = 0;
+       ct->ct_wait.tv_usec = 0;
+       ct->ct_addr = *raddr;
+
+       /*
+        * Initialize call message
+        */
+       (void)gettimeofday(&now, (struct timezone *)0);
+       call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+       call_msg.rm_direction = CALL;
+       call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       call_msg.rm_call.cb_prog = prog;
+       call_msg.rm_call.cb_vers = vers;
+
+       /*
+        * pre-serialize the static part of the call msg and stash it away
+        */
+       xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
+           XDR_ENCODE);
+       if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
+               if (ct->ct_closeit) {
+                       (void)close(*sockp);
+               }
+               goto fooy;
+       }
+       ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
+       XDR_DESTROY(&(ct->ct_xdrs));
+
+       /*
+        * Create a client handle which uses xdrrec for serialization
+        * and authnone for authentication.
+        */
+       xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
+           (void *)ct, readtcp, writetcp);
+       ct->ct_sendsz = sendsz;
+       ct->ct_recvsz = recvsz;
+       h->cl_ops = &tcp_ops;
+       h->cl_private = (void *) ct;
+       h->cl_auth = authnone_create();
+       return (h);
+
+fooy:
+       /*
+        * Something goofed, free stuff and barf
+        */
+       mem_free((void *)ct, sizeof(struct ct_data));
+       mem_free((void *)h, sizeof(CLIENT));
+       return ((CLIENT *)NULL);
+}
+
+static enum clnt_stat
+get_areply(
+       CLIENT *h,
+       struct rpc_msg *reply_msg)
+{
+       struct ct_data *ct = (struct ct_data *) h->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+
+       /* CONSTCOND */
+       while (TRUE) {
+               reply_msg->acpted_rply.ar_verf = _null_auth;
+               reply_msg->acpted_rply.ar_results.where = NULL;
+               reply_msg->acpted_rply.ar_results.proc = xdr_void;
+               if (! xdrrec_skiprecord(xdrs)) {
+                       return (ct->ct_error.re_status);
+               }
+               /* now decode and validate the response header */
+               if (! xdr_replymsg(xdrs, reply_msg)) {
+                       if (ct->ct_error.re_status == RPC_SUCCESS)
+                               continue;
+                }
+               return (ct->ct_error.re_status);
+       }
+}
+
+static enum clnt_stat
+proc_header(
+       CLIENT *h,
+       struct rpc_msg *reply_msg,
+       xdrproc_t xdr_results,
+       void * results_ptr)
+{
+       struct ct_data *ct = (struct ct_data *) h->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+
+       /*
+        * process header
+        */
+       _seterr_reply(reply_msg, &(ct->ct_error));
+       if (ct->ct_error.re_status == RPC_SUCCESS) {
+               if (! AUTH_VALIDATE(h->cl_auth,
+                                       &reply_msg->acpted_rply.ar_verf)) {
+                       ct->ct_error.re_status = RPC_AUTHERROR;
+                       ct->ct_error.re_why = AUTH_INVALIDRESP;
+               } else if (! (*xdr_results)(xdrs, results_ptr)) {
+                       if (ct->ct_error.re_status == RPC_SUCCESS)
+                               ct->ct_error.re_status = RPC_CANTDECODERES;
+               }
+               /* free verifier ... */
+               if (reply_msg->acpted_rply.ar_verf.oa_base != NULL) {
+                       xdrs->x_op = XDR_FREE;
+                       (void)xdr_opaque_auth(xdrs,
+                                       &(reply_msg->acpted_rply.ar_verf));
+               }
+       }  /* end successful completion */
+       return (ct->ct_error.re_status);
+}
+
+static enum clnt_stat
+sfs_ctcp_call(
+       CLIENT *h,
+       uint32_t proc,
+       xdrproc_t xdr_args,
+       void * args_ptr,
+       xdrproc_t xdr_results,
+       void * results_ptr,
+       struct timeval timeout)
+{
+       struct ct_data *ct = (struct ct_data *) h->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+       struct rpc_msg reply_msg;
+       uint32_t x_id;
+       uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);        /* yuk */
+       bool_t shipnow;
+
+       ct->ct_wait = timeout;
+
+       shipnow =
+           (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
+           && timeout.tv_usec == 0) ? FALSE : TRUE;
+
+       xdrs->x_op = XDR_ENCODE;
+       ct->ct_error.re_status = RPC_SUCCESS;
+       x_id = ntohl(--(*msg_x_id));
+       if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
+           (! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
+           (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
+           (! (*xdr_args)(xdrs, args_ptr))) {
+               if (ct->ct_error.re_status == RPC_SUCCESS)
+                       ct->ct_error.re_status = RPC_CANTENCODEARGS;
+               (void)xdrrec_endofrecord(xdrs, TRUE);
+               return (ct->ct_error.re_status);
+       }
+       if (! xdrrec_endofrecord(xdrs, TRUE))
+               return (ct->ct_error.re_status = RPC_CANTSEND);
+       /*
+        * Hack to provide rpc-based message passing
+        */
+       if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+               if (! shipnow && results_ptr == NULL)
+                       return (RPC_SUCCESS);
+
+               /*
+                * Double hack, send back xid in results_prt if non-NULL
+                */
+               *(uint32_t *)results_ptr = x_id;
+               return(ct->ct_error.re_status = RPC_TIMEDOUT);
+       }
+
+
+       /*
+        * Keep receiving until we get a valid transaction id
+        */
+       xdrs->x_op = XDR_DECODE;
+       /* CONSTCOND */
+       while (TRUE) {
+               enum clnt_stat res;
+
+               if ((res = get_areply(h, &reply_msg)) != RPC_SUCCESS)
+                       return (res);
+
+               if (reply_msg.rm_xid == x_id)
+                       break;
+       }
+
+       /*
+        * process header
+        */
+       return (proc_header(h, &reply_msg, xdr_results, results_ptr));
+}
+
+static void
+sfs_ctcp_geterr(
+       CLIENT *h,
+       struct rpc_err *errp)
+{
+       struct ct_data *ct =
+           (struct ct_data *) h->cl_private;
+
+       *errp = ct->ct_error;
+}
+
+static bool_t
+sfs_ctcp_freeres(
+       CLIENT *cl,
+       xdrproc_t xdr_res,
+       void * res_ptr)
+{
+       struct ct_data *ct = (struct ct_data *)cl->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/* ARGSUSED */
+static void
+sfs_ctcp_abort(CLIENT *h)
+{
+}
+
+static bool_t
+sfs_ctcp_control(
+       CLIENT *cl,
+       uint_t request,
+       void *info)
+{
+       struct ct_data *ct = (struct ct_data *)cl->cl_private;
+
+       switch (request) {
+       case CLGET_SERVER_ADDR:
+               *(struct sockaddr_in *)info = ct->ct_addr;
+               break;
+       default:
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+
+static void
+sfs_ctcp_destroy(
+       CLIENT *h)
+{
+       struct ct_data *ct =
+           (struct ct_data *) h->cl_private;
+
+       if (ct->ct_closeit) {
+               (void)close(ct->ct_sock);
+       }
+       XDR_DESTROY(&(ct->ct_xdrs));
+       mem_free((void *)ct, sizeof(struct ct_data));
+       mem_free((void *)h, sizeof(CLIENT));
+}
+
+/*
+ * Interface between xdr serializer and tcp connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readtcp(struct ct_data *ct,
+       char * buf,
+       int len)
+{
+#ifdef FD_SETSIZE
+       fd_set mask;
+       fd_set readfds;
+
+       FD_ZERO(&mask);
+       FD_SET(ct->ct_sock, &mask);
+#else
+       int mask = 1 << (ct->ct_sock);
+       int readfds;
+#endif /* def FD_SETSIZE */
+
+       if (len == 0)
+               return (0);
+
+       /* CONSTCOND */
+       while (TRUE) {
+               readfds = mask;
+               switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
+                              &(ct->ct_wait))) {
+               case 0:
+                       ct->ct_error.re_status = RPC_TIMEDOUT;
+                       return (-1);
+
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       ct->ct_error.re_status = RPC_CANTRECV;
+                       ct->ct_error.re_errno = errno;
+                       goto lost;
+               }
+               break;
+       }
+       switch (len = read(ct->ct_sock, buf, len)) {
+
+       case 0:
+               /* premature eof */
+               ct->ct_error.re_errno = ECONNRESET;
+               ct->ct_error.re_status = RPC_CANTRECV;
+               len = -1;  /* it's really an error */
+               goto lost;
+
+       case -1:
+               ct->ct_error.re_errno = errno;
+               ct->ct_error.re_status = RPC_CANTRECV;
+               goto lost;
+       }
+       return (len);
+lost:
+       /*
+        * We have lost our connection to the server.  Try and
+        * reestablish it.
+        */
+       (void) close(ct->ct_sock);
+       ct->ct_addr = ct->ct_oaddr;
+       ct->ct_sock = -1;
+       XDR_DESTROY(&(ct->ct_xdrs));
+
+       (void) sfs_ctcp_make_conn(ct, &ct->ct_addr, &ct->ct_sock);
+       /*
+        * Create a client handle which uses xdrrec for
+        * serialization and authnone for authentication.
+        */
+       xdrrec_create(&(ct->ct_xdrs), ct->ct_sendsz, ct->ct_recvsz,
+                                               (void *)ct, readtcp, writetcp);
+       return (-1);
+}
+
+static int
+writetcp(
+       struct ct_data *ct,
+       char * buf,
+       int len)
+{
+       int i, cnt;
+
+       for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+               if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
+                       /*
+                        * We have lost our connection to the server.  Try and
+                        * reestablish it.
+                        */
+                       (void) close(ct->ct_sock);
+                       ct->ct_addr = ct->ct_oaddr;
+                       ct->ct_sock = -1;
+                       XDR_DESTROY(&(ct->ct_xdrs));
+
+                       (void) sfs_ctcp_make_conn(ct, &ct->ct_addr,
+                                                               &ct->ct_sock);
+                       /*
+                        * Create a client handle which uses xdrrec for
+                        * serialization and authnone for authentication.
+                        */
+                       xdrrec_create(&(ct->ct_xdrs), ct->ct_sendsz,
+                                               ct->ct_recvsz,
+                                               (void *)ct, readtcp, writetcp);
+                       ct->ct_error.re_errno = errno;
+                       ct->ct_error.re_status = RPC_CANTSEND;
+                       return (-1);
+               }
+       }
+       return (len);
+}
+
+/* ARGSUSED */
+static bool_t
+sfs_ctcp_getreply(
+        CLIENT *cl,
+        xdrproc_t xdr_results,
+        void *results_ptr,
+       int cnt,
+       uint32_t *xids,
+        uint32_t *xid,
+       struct timeval *tv)
+{
+       struct ct_data *ct = (struct ct_data *) cl->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+       struct rpc_msg reply_msg;
+       enum clnt_stat res;
+       int i;
+
+       /*
+        * Receive just one returning transaction id
+        */
+       xdrs->x_op = XDR_DECODE;
+       ct->ct_error.re_status = RPC_SUCCESS;
+       ct->ct_wait.tv_sec = tv->tv_sec;
+       ct->ct_wait.tv_usec = tv->tv_usec;
+
+       if ((res = get_areply(cl, &reply_msg)) != RPC_SUCCESS)
+               return (res);
+
+       *xid = reply_msg.rm_xid;
+
+       /*
+        * Check to make sure xid matchs one that we are interested in
+        */
+       for (i = 0; i < cnt; i++) {
+               if (xids[i] == *xid)
+                       break;
+       }
+
+       if (i == cnt)
+               return (RPC_CANTDECODERES);
+
+       /*
+        * process header
+        */
+       return (proc_header(cl, &reply_msg, xdr_results, results_ptr));
+}
+/* ARGSUSED */
+static int
+sfs_ctcp_poll(
+        CLIENT *cl,
+        uint32_t usecs)
+{
+       struct ct_data *ct = (struct ct_data *)cl->cl_private;
+       XDR *xdrs = &(ct->ct_xdrs);
+       struct timeval tv;
+#ifdef FD_SETSIZE
+       fd_set mask;
+       fd_set readfds;
+
+       FD_ZERO(&mask);
+       FD_SET(ct->ct_sock, &mask);
+#else
+       int mask = 1 << (ct->ct_sock);
+       int readfds;
+#endif /* def FD_SETSIZE */
+
+       if (xdrrec_eof(xdrs) == FALSE)
+               return (1);
+
+       tv.tv_sec = 0;
+       if (usecs > 1000000)
+               tv.tv_sec = usecs / 1000000;
+       tv.tv_usec = usecs % 1000000;
+
+       readfds = mask;
+       return (select(_rpc_dtablesize(), &readfds, NULL, NULL, &tv));
+}
diff --git a/TBBT/trace_play/rpc/sfs_cudp.c b/TBBT/trace_play/rpc/sfs_cudp.c
new file mode 100755 (executable)
index 0000000..1dee989
--- /dev/null
@@ -0,0 +1,604 @@
+#ifndef lint
+static char sfs_cudp_id[] = "@(#)sfs_cudp.c    2.1     97/10/23";
+#endif
+
+/* @(#)clnt_udp.c      2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * clnt_udp.c, Implements a UDP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifndef FreeBSD
+#include <stropts.h>
+#endif  /* ndef FreeBSD */
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+#include "rpc/pmap_clnt.h"
+#include <errno.h>
+#include "rfs_c_def.h" /* Just for the define of RFS */
+/*
+ * UDP bases client side rpc operations
+ */
+static enum clnt_stat sfs_cudp_call(CLIENT *, uint32_t, xdrproc_t,
+                                       void *, xdrproc_t, void *,
+                                       struct timeval);
+static void            sfs_cudp_abort(CLIENT *h);
+static void            sfs_cudp_geterr(CLIENT *, struct rpc_err *);
+static bool_t          sfs_cudp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t          sfs_cudp_control(CLIENT *, uint_t, void *);
+static void            sfs_cudp_destroy(CLIENT *);
+static bool_t           sfs_cudp_getreply(CLIENT *, xdrproc_t, void *,
+                               int, uint32_t *, uint32_t *, struct timeval *);
+static int              sfs_cudp_poll(CLIENT *, uint32_t);
+
+static struct clnt_ops sfs_cudp_ops = {
+       sfs_cudp_call,
+       sfs_cudp_abort,
+       sfs_cudp_geterr,
+       sfs_cudp_freeres,
+       sfs_cudp_destroy,
+       sfs_cudp_control,
+       sfs_cudp_getreply,
+       sfs_cudp_poll
+};
+
+/* 
+ * Private data kept per client handle
+ */
+struct cu_data {
+       int                cu_sock;
+       bool_t             cu_closeit;
+       struct sockaddr_in cu_raddr;
+       int                cu_rlen;
+       struct rpc_err cu_error;
+       XDR                cu_outxdrs;
+       uint_t             cu_xdrpos;
+       uint_t             cu_sendsz;
+       char               *cu_outbuf;
+       uint_t             cu_recvsz;
+       char               cu_inbuf[1];
+};
+
+/*
+ * Create a UDP based client handle.
+ * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If raddr->sin_port is 0 a binder on the remote machine
+ * is consulted for the correct port number.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ *     Caller may wish to set this something more useful.
+ *
+ * wait is the amount of time used between retransmitting a call if
+ * no response has been heard;  retransmition occurs until the actual
+ * rpc call times out.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received.
+ */
+/* ARGSUSED */
+CLIENT *
+sfs_cudp_bufcreate(
+       struct sockaddr_in *raddr,
+       uint32_t program,
+       uint32_t version,
+       struct timeval wait,
+       int *sockp,
+       uint_t sendsz,
+       uint_t recvsz)
+{
+       CLIENT *cl;
+       struct cu_data *cu;
+       struct timeval now;
+       struct rpc_msg call_msg;
+       int min_buf_sz;
+       int new_buf_sz;
+       int type;
+       int i;
+       int error;
+#if defined(UNIXWARE) || defined(AIX)
+       size_t optlen;
+#else
+       int optlen;
+#endif
+
+       cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
+       if (cl == NULL) {
+               (void) fprintf(stderr, "sfs_cudp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       sendsz = ((sendsz + 3) / 4) * 4;
+       recvsz = ((recvsz + 3) / 4) * 4;
+       cu = (struct cu_data *)mem_alloc(sizeof(struct cu_data) +
+                                                       sendsz + recvsz);
+       if (cu == NULL) {
+               (void) fprintf(stderr, "sfs_cudp_create: out of memory\n");
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+               rpc_createerr.cf_error.re_errno = errno;
+               goto fooy;
+       }
+       cu->cu_outbuf = &cu->cu_inbuf[recvsz];
+
+       (void)gettimeofday(&now, (struct timezone *)0);
+       if (raddr->sin_port == 0) {
+               uint16_t port;
+               if ((port =
+                   pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
+                       goto fooy;
+               }
+               raddr->sin_port = htons(port);
+       }
+       cl->cl_ops = &sfs_cudp_ops;
+       cl->cl_private = (void *)cu;
+       cu->cu_raddr = *raddr;
+       cu->cu_rlen = sizeof (cu->cu_raddr);
+       cu->cu_sendsz = sendsz;
+       cu->cu_recvsz = recvsz;
+       call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+       call_msg.rm_direction = CALL;
+       call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       call_msg.rm_call.cb_prog = program;
+       call_msg.rm_call.cb_vers = version;
+       xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
+           sendsz, XDR_ENCODE);
+       if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
+               goto fooy;
+       }
+       cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
+       if (*sockp < 0) {
+#if defined(O_NONBLOCK)
+               int flags;
+#elif defined(FIONBIO)
+               int dontblock = 1;
+#endif
+
+               *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+               if (*sockp < 0) {
+                       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+                       rpc_createerr.cf_error.re_errno = errno;
+                       goto fooy;
+               }
+               /* attempt to bind to prov port */
+               (void)bindresvport(*sockp, (struct sockaddr_in *)0);
+               /* the sockets rpc controls are non-blocking */
+#if defined(O_NONBLOCK)
+               flags = fcntl(*sockp, F_GETFL, 0) | O_NONBLOCK;
+               (void)fcntl(*sockp, F_SETFL, flags);
+#elif defined(FIONBIO)
+               (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
+#endif
+               cu->cu_closeit = TRUE;
+       } else {
+               cu->cu_closeit = FALSE;
+       }
+       cu->cu_sock = *sockp;
+       /*
+        * Need to try to size the socket buffers based on the number of
+        * outstanding requests desired.  NFS reads and writes can do as
+        * much as 8K per request which can quickly run us out of space
+        * on the socket buffer queue.  Use the maximum number of bio style
+        * requests * NFS_MAXDATA plus a pad as a starting point for desired
+        * socket buffer size and then back off by NFS_MAXDATA until the buffer
+        * sizes are successfully set.  Note, the algorithm never sets the
+        * buffer size to less than the OS default.
+        */  
+       type = SO_SNDBUF;
+       for (i = 0; i < 2; i++) {
+               optlen = sizeof(min_buf_sz);
+#if defined(UNIXWARE)
+               if (getsockopt(cu->cu_sock, SOL_SOCKET, type,
+                               (void *)&min_buf_sz, &optlen) < 0) {
+                       /* guess the default */
+                       min_buf_sz = 18 * 1024;
+               }
+#else
+               if (getsockopt(cu->cu_sock, SOL_SOCKET, type,
+                               (char *)&min_buf_sz, &optlen) < 0) {
+                       /* guess the default */
+                       min_buf_sz = 18 * 1024;
+               }
+#endif
+
+               new_buf_sz = 512 * 1024;
+               if (new_buf_sz > min_buf_sz) {
+                       do {
+                               error = setsockopt(cu->cu_sock, SOL_SOCKET,
+                                               type, (char *)&new_buf_sz,
+                                               sizeof(int));
+                               new_buf_sz -= (8 * 1024);
+                       } while (error != 0 && new_buf_sz > min_buf_sz);
+               }
+
+               type = SO_RCVBUF;
+       }
+
+       cl->cl_auth = authnone_create();
+       return (cl);
+fooy:
+       if (cu)
+               mem_free((void *)cu, sizeof(struct cu_data) + sendsz + recvsz);
+       if (cl)
+               mem_free((void *)cl, sizeof(CLIENT));
+       return ((CLIENT *)NULL);
+}
+
+CLIENT *
+sfs_cudp_create(
+       struct sockaddr_in *raddr,
+       uint32_t program,
+       uint32_t version,
+       struct timeval wait,
+       int *sockp)
+{
+
+       return(sfs_cudp_bufcreate(raddr, program, version, wait, sockp,
+           UDPMSGSIZE, UDPMSGSIZE));
+}
+
+#ifdef RFS
+enum clnt_stat get_areply_udp (
+               CLIENT * cl,
+               uint32_t *xid,
+               struct timeval *timeout) 
+{
+       return get_areply (cl, xid, timeout);
+}
+#endif
+
+static enum clnt_stat
+get_areply(
+        CLIENT *cl,
+        uint32_t *xid,
+       struct timeval *timeout)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       int inlen;
+#if defined(AIX)
+       size_t fromlen;
+#else
+       int fromlen;
+#endif
+       struct sockaddr_in from;
+#ifdef FD_SETSIZE
+       fd_set readfds;
+       fd_set mask;
+#else
+       int readfds;
+       int mask;
+#endif /* def FD_SETSIZE */
+
+#ifdef FD_SETSIZE
+       FD_ZERO(&mask);
+       FD_SET(cu->cu_sock, &mask);
+#else
+       mask = 1 << cu->cu_sock;
+#endif /* def FD_SETSIZE */
+
+       for (;;) {
+               readfds = mask;
+               switch (select(_rpc_dtablesize(), &readfds, NULL, 
+                              NULL, timeout)) {
+
+               case 0:
+                       return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
+               case -1:
+                       if (errno == EINTR)
+                               continue;       
+                       cu->cu_error.re_errno = errno;
+                       return (cu->cu_error.re_status = RPC_CANTRECV);
+               }
+               do {
+                       fromlen = sizeof(struct sockaddr);
+                       inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
+                               (int) cu->cu_recvsz, 0,
+                               (struct sockaddr *)&from, &fromlen);
+               } while (inlen < 0 && errno == EINTR);
+               if (inlen < 0) {
+                       if (errno == EWOULDBLOCK)
+                               continue;       
+                       cu->cu_error.re_errno = errno;
+                       return (cu->cu_error.re_status = RPC_CANTRECV);
+               }
+
+               if (inlen < sizeof(uint32_t))
+                       continue;       
+
+               *xid = ntohl(*((uint32_t *)(cu->cu_inbuf)));
+               return (RPC_SUCCESS);
+       }
+}
+
+enum clnt_stat
+proc_header(
+       CLIENT *cl,
+       xdrproc_t xdr_results,
+       void *results_ptr)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       XDR *xdrs = &(cu->cu_outxdrs);
+       struct rpc_msg reply_msg;
+       XDR reply_xdrs;
+       bool_t ok;
+
+       /*
+        * now decode and validate the response
+        */
+       xdrmem_create(&reply_xdrs, cu->cu_inbuf, cu->cu_recvsz, XDR_DECODE);
+
+       reply_msg.acpted_rply.ar_verf = _null_auth;
+       reply_msg.acpted_rply.ar_results.where = results_ptr;
+       reply_msg.acpted_rply.ar_results.proc = xdr_results;
+
+       ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+       /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
+       if (!ok) {
+               return (cu->cu_error.re_status = RPC_CANTDECODERES);
+       }
+
+       _seterr_reply(&reply_msg, &(cu->cu_error));
+
+       if (cu->cu_error.re_status == RPC_SUCCESS) {
+               if (! AUTH_VALIDATE(cl->cl_auth,
+                               &reply_msg.acpted_rply.ar_verf)) {
+                       cu->cu_error.re_status = RPC_AUTHERROR;
+                       cu->cu_error.re_why = AUTH_INVALIDRESP;
+               }
+               if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
+                       xdrs->x_op = XDR_FREE;
+                       (void)xdr_opaque_auth(xdrs,
+                               &(reply_msg.acpted_rply.ar_verf));
+               }
+       }
+
+       return (cu->cu_error.re_status);
+}
+
+/*
+ * Non-standard changes.  Make a call an at-most-once with a per call
+ * timer.  Ignore the timeout set at creation. Never retransmit.
+ */
+static enum clnt_stat 
+sfs_cudp_call(
+       CLIENT          *cl,            /* client handle */
+       uint32_t        proc,           /* procedure number */
+       xdrproc_t       xargs,          /* xdr routine for args */
+       void *          argsp,          /* pointer to args */
+       xdrproc_t       xresults,       /* xdr routine for results */
+       void *          resultsp,       /* pointer to results */
+       struct timeval  timeout)        /* seconds to wait before giving up */
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       XDR *xdrs = &(cu->cu_outxdrs);
+       int outlen;
+       uint32_t x_id, r_xid;
+
+       xdrs->x_op = XDR_ENCODE;
+       XDR_SETPOS(xdrs, cu->cu_xdrpos);
+
+       /*
+        * the transaction is the first thing in the out buffer
+        */
+       (*(uint32_t *)(cu->cu_outbuf))++;
+       x_id = ntohl(*(uint32_t *)(cu->cu_outbuf));
+
+       if ((! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
+           (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+           (! (*xargs)(xdrs, argsp)))
+               return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+
+       outlen = (int)XDR_GETPOS(xdrs);
+
+       if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
+           (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) {
+               cu->cu_error.re_errno = errno;
+               return (cu->cu_error.re_status = RPC_CANTSEND);
+       }
+
+       /*
+        * Hack to provide rpc-based message passing
+        */
+       if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+                /* 
+                 * Double hack, send back xid in results_prt if non-NULL
+                 */ 
+                if (resultsp != NULL) 
+                        *(uint32_t *)resultsp = x_id; 
+
+               return (cu->cu_error.re_status = RPC_TIMEDOUT);
+       }
+
+       /* CONSTCOND */
+       while (TRUE) {
+               enum clnt_stat res;
+
+               if ((res = get_areply(cl, &r_xid, &timeout)) != RPC_SUCCESS)
+                       return (res);
+
+               if (r_xid == x_id)
+                       break;
+       }
+
+       /*
+        * process header
+        */
+       return (proc_header(cl, xresults, resultsp));
+}
+
+static void
+sfs_cudp_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       *errp = cu->cu_error;
+}
+
+
+static bool_t
+sfs_cudp_freeres(
+       CLIENT *cl,
+       xdrproc_t xdr_res,
+       void * res_ptr)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       XDR *xdrs = &(cu->cu_outxdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/* ARGSUSED */
+static void 
+sfs_cudp_abort(CLIENT *h)
+{
+}
+
+static bool_t
+sfs_cudp_control(
+       CLIENT *cl,
+       uint_t request,
+       void *info)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       switch (request) {
+       case CLGET_SERVER_ADDR:
+               *(struct sockaddr_in *)info = cu->cu_raddr;
+               break;
+       default:
+               return (FALSE);
+       }
+       return (TRUE);
+}
+       
+static void
+sfs_cudp_destroy(CLIENT *cl)
+{
+       struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+       if (cu->cu_closeit) {
+               (void)close(cu->cu_sock);
+       }
+       XDR_DESTROY(&(cu->cu_outxdrs));
+       mem_free((void *)cu, (sizeof(struct cu_data) + cu->cu_sendsz + cu->cu_recvsz));
+       mem_free((void *)cl, sizeof(CLIENT));
+}
+
+/* ARGSUSED */
+static bool_t
+sfs_cudp_getreply(
+        CLIENT *cl,
+        xdrproc_t xproc,
+        void *xres,
+       int cnt,
+       uint32_t *xids,
+        uint32_t *xid,
+       struct timeval *tv)
+{
+        struct cu_data *cu = (struct cu_data *)cl->cl_private;
+       bool_t res;
+       int i;
+
+       cu->cu_error.re_status = RPC_SUCCESS;
+
+       if ((res = get_areply(cl, xid, tv)) != RPC_SUCCESS)
+               return (res);
+
+       /*
+        * Check to make sure xid matchs one that we are interested in
+        */
+       for (i = 0; i < cnt; i++) {
+               if (xids[i] == *xid)
+                       break;
+       }
+
+       if (i == cnt)
+               return (RPC_CANTDECODERES);
+
+       /*
+        * process header
+        */
+       return (proc_header(cl, xproc, xres));
+}
+static int
+sfs_cudp_poll(
+        CLIENT *cl,
+        uint32_t usecs)
+{
+        struct cu_data *cu = (struct cu_data *)cl->cl_private;
+        struct timeval tv;
+#ifdef FD_SETSIZE
+        fd_set mask;
+        fd_set readfds;
+        FD_ZERO(&mask);
+        FD_SET(cu->cu_sock, &mask);
+#else
+        int mask = 1 << (cu->cu_sock);
+        int readfds;
+#endif /* def FD_SETSIZE */
+        tv.tv_sec = 0; 
+        if (usecs > 1000000) 
+                tv.tv_sec = usecs / 1000000; 
+        tv.tv_usec = usecs % 1000000; 
+        readfds = mask;
+        return (select(_rpc_dtablesize(), &readfds, NULL, NULL, &tv));
+}
diff --git a/TBBT/trace_play/rpc/svc.c b/TBBT/trace_play/rpc/svc.c
new file mode 100755 (executable)
index 0000000..9a8d905
--- /dev/null
@@ -0,0 +1,479 @@
+#ifndef lint
+static char sfs_svc_c_id[] = "@(#)svc.c     2.1     97/10/23";
+#endif
+/* @(#)svc.c   2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc.c, Server-side remote procedure call interface.
+ *
+ * There are two sets of procedures here.  The xprt routines are
+ * for handling transport handles.  The svc routines handle the
+ * list of service routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "rpc/rpc.h"
+#include "rpc/pmap_clnt.h"
+
+#ifdef FD_SETSIZE
+static SVCXPRT **xports;
+#else
+#define NOFILE 32
+
+static SVCXPRT *xports[NOFILE];
+#endif /* def FD_SETSIZE */
+
+#define NULL_SVC ((struct svc_callout *)0)
+#define        RQCRED_SIZE     400             /* this size is excessive */
+
+/*
+ * The services list
+ * Each entry represents a set of procedures (an rpc program).
+ * The dispatch routine takes request structs and runs the
+ * apropriate procedure.
+ */
+static struct svc_callout {
+       struct svc_callout *sc_next;
+       uint32_t            sc_prog;
+       uint32_t            sc_vers;
+       void                (*sc_dispatch)();
+} *svc_head;
+
+static struct svc_callout *svc_find();
+
+/* ***************  SVCXPRT related stuff **************** */
+
+/*
+ * Activate a transport handle.
+ */
+void
+xprt_register(
+       SVCXPRT *xprt)
+{
+       int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+       if (xports == NULL) {
+               xports = (SVCXPRT **)
+                       mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
+       }
+       if (sock < _rpc_dtablesize()) {
+               xports[sock] = xprt;
+               FD_SET(sock, &svc_fdset);
+       }
+#else
+       if (sock < NOFILE) {
+               xports[sock] = xprt;
+               svc_fds |= (1 << sock);
+       }
+#endif /* def FD_SETSIZE */
+
+}
+
+/*
+ * De-activate a transport handle. 
+ */
+void
+xprt_unregister(
+       SVCXPRT *xprt)
+{ 
+       int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+       if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) {
+               xports[sock] = (SVCXPRT *)0;
+               FD_CLR(sock, &svc_fdset);
+       }
+#else
+       if ((sock < NOFILE) && (xports[sock] == xprt)) {
+               xports[sock] = (SVCXPRT *)0;
+               svc_fds &= ~(1 << sock);
+       }
+#endif /* def FD_SETSIZE */
+}
+
+
+/* ********************** CALLOUT list related stuff ************* */
+
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_register(
+       SVCXPRT *xprt,
+       uint32_t prog,
+       uint32_t vers,
+       void (*dispatch)(),
+       int protocol)
+{
+       struct svc_callout *prev;
+       struct svc_callout *s;
+
+       if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
+               if (s->sc_dispatch == dispatch)
+                       goto pmap_it;  /* he is registering another xptr */
+               return (FALSE);
+       }
+       s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
+       if (s == (struct svc_callout *)0) {
+               return (FALSE);
+       }
+       s->sc_prog = prog;
+       s->sc_vers = vers;
+       s->sc_dispatch = dispatch;
+       s->sc_next = svc_head;
+       svc_head = s;
+pmap_it:
+       /* now register the information with the local binder service */
+       if (protocol) {
+               return (pmap_set(prog, vers, protocol, xprt->xp_port));
+       }
+       return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unregister(
+       uint32_t prog,
+       uint32_t vers)
+{
+       struct svc_callout *prev;
+       struct svc_callout *s;
+
+       if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
+               return;
+       if (prev == NULL_SVC) {
+               svc_head = s->sc_next;
+       } else {
+               prev->sc_next = s->sc_next;
+       }
+       s->sc_next = NULL_SVC;
+       mem_free((char *) s, (uint_t) sizeof(struct svc_callout));
+       /* now unregister the information with the local binder service */
+       (void)pmap_unset(prog, vers);
+}
+
+/*
+ * Search the callout list for a program number, return the callout
+ * struct.
+ */
+static struct svc_callout *
+svc_find(
+       uint32_t prog,
+       uint32_t vers,
+       struct svc_callout **prev)
+{
+       struct svc_callout *s, *p;
+
+       p = NULL_SVC;
+       for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
+               if ((s->sc_prog == prog) && (s->sc_vers == vers))
+                       goto done;
+               p = s;
+       }
+done:
+       *prev = p;
+       return (s);
+}
+
+/* ******************* REPLY GENERATION ROUTINES  ************ */
+
+/*
+ * Send a reply to an rpc request
+ */
+bool_t
+svc_sendreply(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_results,
+       void *xdr_location)
+{
+       struct rpc_msg rply; 
+
+       rply.rm_direction = REPLY;  
+       rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+       rply.acpted_rply.ar_verf = xprt->xp_verf; 
+       rply.acpted_rply.ar_stat = SUCCESS;
+       rply.acpted_rply.ar_results.where = xdr_location;
+       rply.acpted_rply.ar_results.proc = xdr_results;
+       return (SVC_REPLY(xprt, &rply)); 
+}
+
+/*
+ * No procedure error reply
+ */
+void
+svcerr_noproc(
+       SVCXPRT *xprt)
+{
+       struct rpc_msg rply;
+
+       rply.rm_direction = REPLY;
+       rply.rm_reply.rp_stat = MSG_ACCEPTED;
+       rply.acpted_rply.ar_verf = xprt->xp_verf;
+       rply.acpted_rply.ar_stat = PROC_UNAVAIL;
+       SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Can't decode args error reply
+ */
+void
+svcerr_decode(
+       SVCXPRT *xprt)
+{
+       struct rpc_msg rply; 
+
+       rply.rm_direction = REPLY; 
+       rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+       rply.acpted_rply.ar_verf = xprt->xp_verf;
+       rply.acpted_rply.ar_stat = GARBAGE_ARGS;
+       SVC_REPLY(xprt, &rply); 
+}
+
+/*
+ * Some system error
+ */
+void
+svcerr_systemerr(
+       SVCXPRT *xprt)
+{
+       struct rpc_msg rply; 
+
+       rply.rm_direction = REPLY; 
+       rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+       rply.acpted_rply.ar_verf = xprt->xp_verf;
+       rply.acpted_rply.ar_stat = SYSTEM_ERR;
+       SVC_REPLY(xprt, &rply); 
+}
+
+/*
+ * Authentication error reply
+ */
+void
+svcerr_auth(
+       SVCXPRT *xprt,
+       enum auth_stat why)
+{
+       struct rpc_msg rply;
+
+       rply.rm_direction = REPLY;
+       rply.rm_reply.rp_stat = MSG_DENIED;
+       rply.rjcted_rply.rj_stat = AUTH_ERROR;
+       rply.rjcted_rply.rj_why = why;
+       SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Auth too weak error reply
+ */
+void
+svcerr_weakauth(
+       SVCXPRT *xprt)
+{
+
+       svcerr_auth(xprt, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void 
+svcerr_noprog(
+       SVCXPRT *xprt)
+{
+       struct rpc_msg rply;  
+
+       rply.rm_direction = REPLY;   
+       rply.rm_reply.rp_stat = MSG_ACCEPTED;  
+       rply.acpted_rply.ar_verf = xprt->xp_verf;  
+       rply.acpted_rply.ar_stat = PROG_UNAVAIL;
+       SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Program version mismatch error reply
+ */
+void  
+svcerr_progvers(
+       SVCXPRT *xprt,
+       uint32_t low_vers,
+       uint32_t high_vers)
+{
+       struct rpc_msg rply;
+
+       rply.rm_direction = REPLY;
+       rply.rm_reply.rp_stat = MSG_ACCEPTED;
+       rply.acpted_rply.ar_verf = xprt->xp_verf;
+       rply.acpted_rply.ar_stat = PROG_MISMATCH;
+       rply.acpted_rply.ar_vers.low = low_vers;
+       rply.acpted_rply.ar_vers.high = high_vers;
+       SVC_REPLY(xprt, &rply);
+}
+
+/* ******************* SERVER INPUT STUFF ******************* */
+
+/*
+ * Get server side input from some transport.
+ *
+ * Statement of authentication parameters management:
+ * This function owns and manages all authentication parameters, specifically
+ * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
+ * the "cooked" credentials (rqst->rq_clntcred).
+ * However, this function does not know the structure of the cooked
+ * credentials, so it make the following assumptions: 
+ *   a) the structure is contiguous (no pointers), and
+ *   b) the cred structure size does not exceed RQCRED_SIZE bytes. 
+ * In all events, all three parameters are freed upon exit from this routine.
+ * The storage is trivially management on the call stack in user land, but
+ * is mallocated in kernel land.
+ */
+
+void
+svc_getreqset(
+#ifdef FD_SETSIZE
+       fd_set *readfds)
+{
+#else
+       int *readfds)
+{
+    int readfds_local = *readfds;
+#endif /* def FD_SETSIZE */
+       enum xprt_stat stat;
+       struct rpc_msg msg;
+       int prog_found;
+       uint32_t low_vers;
+       uint32_t high_vers;
+       struct svc_req r;
+       SVCXPRT *xprt;
+       int setsize;
+       int sock;
+       char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
+       msg.rm_call.cb_cred.oa_base = cred_area;
+       msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
+       r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
+
+
+#ifdef FD_SETSIZE
+       setsize = _rpc_dtablesize();    
+       for (sock = 0; sock < setsize; sock++) {
+           if (FD_ISSET(sock, readfds)) {
+#else
+       for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
+           if ((readfds_local & 1) != 0) {
+#endif /* def FD_SETSIZE */
+               /* sock has input waiting */
+               xprt = xports[sock];
+               /* now receive msgs from xprtprt (support batch calls) */
+               do {
+                       if (SVC_RECV(xprt, &msg)) {
+
+                               /* now find the exported program and call it */
+                               struct svc_callout *s;
+                               enum auth_stat why;
+
+                               r.rq_xprt = xprt;
+                               r.rq_prog = msg.rm_call.cb_prog;
+                               r.rq_vers = msg.rm_call.cb_vers;
+                               r.rq_proc = msg.rm_call.cb_proc;
+                               r.rq_cred = msg.rm_call.cb_cred;
+                               /* first authenticate the message */
+                               if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
+                                       svcerr_auth(xprt, why);
+                                       goto call_done;
+                               }
+                               /* now match message with a registered service*/
+                               prog_found = FALSE;
+                               low_vers = 0 - 1;
+                               high_vers = 0;
+                               for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
+                                       if (s->sc_prog == r.rq_prog) {
+                                               if (s->sc_vers == r.rq_vers) {
+                                                       (*s->sc_dispatch)(&r, xprt);
+                                                       goto call_done;
+                                               }  /* found correct version */
+                                               prog_found = TRUE;
+                                               if (s->sc_vers < low_vers)
+                                                       low_vers = s->sc_vers;
+                                               if (s->sc_vers > high_vers)
+                                                       high_vers = s->sc_vers;
+                                       }   /* found correct program */
+                               }
+                               /*
+                                * if we got here, the program or version
+                                * is not served ...
+                                */
+                               if (prog_found)
+                                       svcerr_progvers(xprt,
+                                       low_vers, high_vers);
+                               else
+                                        svcerr_noprog(xprt);
+                               /* Fall through to ... */
+                       }
+               call_done:
+                       if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
+                               SVC_DESTROY(xprt);
+                               break;
+                       }
+               } while (stat == XPRT_MOREREQS);
+           }
+       }
+}
diff --git a/TBBT/trace_play/rpc/svc.h b/TBBT/trace_play/rpc/svc.h
new file mode 100755 (executable)
index 0000000..497a6ca
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * @(#)svc.h     2.1     97/10/23
+ */
+/* @(#)svc.h   2.2 88/07/29 4.0 RPCSRC; from 1.20 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * svc.h, Server-side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef __SVC_HEADER__
+#define __SVC_HEADER__
+
+#include "rpc/rpc_msg.h"
+#include "rpc/xdr.h"
+
+/*
+ * This interface must manage two items concerning remote procedure calling:
+ *
+ * 1) An arbitrary number of transport connections upon which rpc requests
+ * are received.  The two most notable transports are TCP and UDP;  they are
+ * created and registered by routines in svc_tcp.c and svc_udp.c, respectively;
+ * they in turn call xprt_register and xprt_unregister.
+ *
+ * 2) An arbitrary number of locally registered services.  Services are
+ * described by the following four data: program number, version number,
+ * "service dispatch" function, a transport handle, and a boolean that
+ * indicates whether or not the exported program should be registered with a
+ * local binder service;  if true the program's number and version and the
+ * port number from the transport handle are registered with the binder.
+ * These data are registered with the rpc svc system via svc_register.
+ *
+ * A service's dispatch function is called whenever an rpc request comes in
+ * on a transport.  The request's program and version numbers must match
+ * those of the registered service.  The dispatch function is passed two
+ * parameters, struct svc_req * and SVCXPRT *, defined below.
+ */
+
+enum xprt_stat {
+       XPRT_DIED,
+       XPRT_MOREREQS,
+       XPRT_IDLE
+};
+
+/*
+ * Server side transport handle
+ */
+typedef struct SVCXPRT {
+       int             xp_sock;
+       uint16_t        xp_port;         /* associated port number */
+       struct xp_ops   *xp_ops;
+#if defined(AIX)
+       size_t          xp_addrlen;      /* length of remote address */
+#else
+       int             xp_addrlen;      /* length of remote address */
+#endif
+       struct sockaddr_in xp_raddr;     /* remote address */
+       struct opaque_auth xp_verf;      /* raw response verifier */
+       void *          xp_p1;           /* private */
+       void *          xp_p2;           /* private */
+} SVCXPRT;
+
+struct xp_ops {
+       bool_t  (*xp_recv)(SVCXPRT *, struct rpc_msg *);
+       enum xprt_stat (*xp_stat)(SVCXPRT *);
+       bool_t  (*xp_getargs)(SVCXPRT *, xdrproc_t, void *);
+       bool_t  (*xp_reply)(SVCXPRT *, struct rpc_msg *);
+       bool_t  (*xp_freeargs)(SVCXPRT *, xdrproc_t, void *);
+       void    (*xp_destroy)(SVCXPRT *);
+};
+/*
+ *  Approved way of getting address of caller
+ */
+#define svc_getcaller(x) (&(x)->xp_raddr)
+
+/*
+ * Operations defined on an SVCXPRT handle
+ *
+ * SVCXPRT             *xprt;
+ * struct rpc_msg      *msg;
+ * xdrproc_t            xargs;
+ * void *               argsp;
+ */
+#define SVC_RECV(xprt, msg)                            \
+       (*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+#define svc_recv(xprt, msg)                            \
+       (*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+
+#define SVC_STAT(xprt)                                 \
+       (*(xprt)->xp_ops->xp_stat)(xprt)
+#define svc_stat(xprt)                                 \
+       (*(xprt)->xp_ops->xp_stat)(xprt)
+
+#define SVC_GETARGS(xprt, xargs, argsp)                        \
+       (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+#define svc_getargs(xprt, xargs, argsp)                        \
+       (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+
+#define SVC_REPLY(xprt, msg)                           \
+       (*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+#define svc_reply(xprt, msg)                           \
+       (*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+
+#define SVC_FREEARGS(xprt, xargs, argsp)               \
+       (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+#define svc_freeargs(xprt, xargs, argsp)               \
+       (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+
+#define SVC_DESTROY(xprt)                              \
+       (*(xprt)->xp_ops->xp_destroy)(xprt)
+#define svc_destroy(xprt)                              \
+       (*(xprt)->xp_ops->xp_destroy)(xprt)
+
+
+/*
+ * Service request
+ */
+struct svc_req {
+       uint32_t        rq_prog;        /* service program number */
+       uint32_t        rq_vers;        /* service protocol version */
+       uint32_t        rq_proc;        /* the desired procedure */
+       struct opaque_auth rq_cred;     /* raw creds from the wire */
+       void *          rq_clntcred;    /* read only cooked cred */
+       SVCXPRT *rq_xprt;               /* associated transport */
+};
+
+
+/*
+ * Service registration
+ *
+ * svc_register(xprt, prog, vers, dispatch, protocol)
+ *     SVCXPRT *xprt;
+ *     uint32_t prog;
+ *     uint32_t vers;
+ *     void (*dispatch)();
+ *     int protocol;
+ */
+extern bool_t  svc_register(SVCXPRT *, uint32_t, uint32_t, void (*)(), int);
+
+/*
+ * Service un-registration
+ *
+ * svc_unregister(prog, vers)
+ *     uint32_t prog;
+ *     uint32_t vers;
+ */
+extern void    svc_unregister(uint32_t, uint32_t);
+
+/*
+ * Transport registration.
+ *
+ * xprt_register(xprt)
+ *     SVCXPRT *xprt;
+ */
+extern void    xprt_register(SVCXPRT *);
+
+/*
+ * Transport un-register
+ *
+ * xprt_unregister(xprt)
+ *     SVCXPRT *xprt;
+ */
+extern void    xprt_unregister(SVCXPRT *);
+
+
+
+
+/*
+ * When the service routine is called, it must first check to see if it
+ * knows about the procedure;  if not, it should call svcerr_noproc
+ * and return.  If so, it should deserialize its arguments via 
+ * SVC_GETARGS (defined above).  If the deserialization does not work,
+ * svcerr_decode should be called followed by a return.  Successful
+ * decoding of the arguments should be followed the execution of the
+ * procedure's code and a call to svc_sendreply.
+ *
+ * Also, if the service refuses to execute the procedure due to too-
+ * weak authentication parameters, svcerr_weakauth should be called.
+ * Note: do not confuse access-control failure with weak authentication!
+ *
+ * NB: In pure implementations of rpc, the caller always waits for a reply
+ * msg.  This message is sent when svc_sendreply is called.  
+ * Therefore pure service implementations should always call
+ * svc_sendreply even if the function logically returns void;  use
+ * xdr.h - xdr_void for the xdr routine.  HOWEVER, tcp based rpc allows
+ * for the abuse of pure rpc via batched calling or pipelining.  In the
+ * case of a batched call, svc_sendreply should NOT be called since
+ * this would send a return message, which is what batching tries to avoid.
+ * It is the service/protocol writer's responsibility to know which calls are
+ * batched and which are not.  Warning: responding to batch calls may
+ * deadlock the caller and server processes!
+ */
+
+extern bool_t  svc_sendreply(SVCXPRT *, xdrproc_t, void *);
+extern void    svcerr_decode(SVCXPRT *);
+extern void    svcerr_weakauth(SVCXPRT *);
+extern void    svcerr_noproc(SVCXPRT *);
+extern void    svcerr_progvers(SVCXPRT *, uint32_t, uint32_t);
+extern void    svcerr_auth(SVCXPRT *, enum auth_stat);
+extern void    svcerr_noprog(SVCXPRT *);
+extern void    svcerr_systemerr(SVCXPRT *);
+    
+/*
+ * Lowest level dispatching -OR- who owns this process anyway.
+ * Somebody has to wait for incoming requests and then call the correct
+ * service routine.  The routine svc_run does infinite waiting; i.e.,
+ * svc_run never returns.
+ * Since another (co-existant) package may wish to selectively wait for
+ * incoming calls or other events outside of the rpc architecture, the
+ * routine svc_getreq is provided.  It must be passed readfds, the
+ * "in-place" results of a select system call (see select, section 2).
+ */
+
+/*
+ * Global keeper of rpc service descriptors in use
+ * dynamic; must be inspected before each call to select 
+ */
+#ifdef FD_SETSIZE
+extern fd_set svc_fdset;
+#define svc_fds svc_fdset.fds_bits[0]  /* compatibility */
+#else
+extern int svc_fds;
+#endif /* def FD_SETSIZE */
+
+/*
+ * a small program implemented by the svc_rpc implementation itself;
+ * also see clnt.h for protocol numbers.
+ */
+extern void rpctest_service();
+
+extern void    svc_getreq(int);
+#ifdef FD_SETSIZE
+extern void    svc_getreqset(fd_set *);/* takes fdset instead of int */
+#else
+extern void    svc_getreqset(int *);
+#endif
+extern void    svc_run(void);   /* never returns */
+
+/*
+ * Socket to use on svcxxx_create call to get default socket
+ */
+#define        RPC_ANYSOCK     -1
+
+/*
+ * These are the existing service side transport implementations
+ */
+
+/*
+ * Memory based rpc for testing and timing.
+ */
+extern SVCXPRT *svcraw_create(void);
+
+/*
+ * Udp based rpc.
+ */
+extern SVCXPRT *svcudp_create(int);
+extern SVCXPRT *svcudp_bufcreate(int, uint_t, uint_t);
+
+/*
+ * Tcp based rpc.
+ */
+extern SVCXPRT *svctcp_create(int, uint_t, uint_t);
+
+extern int svcudp_enablecache(SVCXPRT *, uint32_t);
+
+
+#endif /* !__SVC_HEADER__ */
diff --git a/TBBT/trace_play/rpc/svc_auth.c b/TBBT/trace_play/rpc/svc_auth.c
new file mode 100755 (executable)
index 0000000..2352630
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef lint
+static char sfs_svc_auth_id[] = "@(#)svc_auth.c     2.1     97/10/23";
+#endif
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_auth.c 2.1 88/08/07 4.0 RPCSRC; from 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * svc_auth_nodes.c, Server-side rpc authenticator interface,
+ * *WITHOUT* DES authentication.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "rpc/rpc.h"
+
+/*
+ * svcauthsw is the bdevsw of server side authentication. 
+ * 
+ * Server side authenticators are called from authenticate by
+ * using the client auth struct flavor field to index into svcauthsw.
+ * The server auth flavors must implement a routine that looks  
+ * like: 
+ * 
+ *     enum auth_stat
+ *     flavorx_auth(rqst, msg)
+ *             register struct svc_req *rqst; 
+ *             register struct rpc_msg *msg;
+ *
+ */
+
+extern enum auth_stat _svcauth_null(struct svc_req *, struct rpc_msg *);
+extern enum auth_stat _svcauth_unix(struct svc_req *, struct rpc_msg *);
+extern enum auth_stat _svcauth_short(struct svc_req *, struct rpc_msg *);
+
+static struct {
+       enum auth_stat (*authenticator)(struct svc_req *, struct rpc_msg *);
+} svcauthsw[] = {
+       _svcauth_null,                  /* AUTH_NULL */
+       _svcauth_unix,                  /* AUTH_UNIX */
+       _svcauth_short,                 /* AUTH_SHORT */
+};
+#define        AUTH_MAX        2               /* HIGHEST AUTH NUMBER */
+
+
+/*
+ * The call rpc message, msg has been obtained from the wire.  The msg contains
+ * the raw form of credentials and verifiers.  authenticate returns AUTH_OK
+ * if the msg is successfully authenticated.  If AUTH_OK then the routine also
+ * does the following things:
+ * set rqst->rq_xprt->verf to the appropriate response verifier;
+ * sets rqst->rq_client_cred to the "cooked" form of the credentials.
+ *
+ * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
+ * its length is set appropriately.
+ *
+ * The caller still owns and is responsible for msg->u.cmb.cred and
+ * msg->u.cmb.verf.  The authentication system retains ownership of
+ * rqst->rq_client_cred, the cooked credentials.
+ *
+ * There is an assumption that any flavour less than AUTH_NULL is
+ * invalid.
+ */
+enum auth_stat
+_authenticate(
+       struct svc_req *rqst,
+       struct rpc_msg *msg)
+{
+       register int cred_flavor;
+
+       rqst->rq_cred = msg->rm_call.cb_cred;
+       rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
+       rqst->rq_xprt->xp_verf.oa_length = 0;
+       cred_flavor = rqst->rq_cred.oa_flavor;
+       if ((cred_flavor <= AUTH_MAX) && (cred_flavor >= AUTH_NULL)) {
+               return ((*(svcauthsw[cred_flavor].authenticator))(rqst, msg));
+       }
+
+       return (AUTH_REJECTEDCRED);
+}
+
+/* ARGSUSED */
+enum auth_stat
+_svcauth_null(
+       struct svc_req *rqst,
+       struct rpc_msg *msg)
+{
+
+       return (AUTH_OK);
+}
diff --git a/TBBT/trace_play/rpc/svc_auth.h b/TBBT/trace_play/rpc/svc_auth.h
new file mode 100755 (executable)
index 0000000..c765e9f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * @(#)svc_auth.h     2.1     97/10/23
+ */
+/* @(#)svc_auth.h      2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)svc_auth.h 1.6 86/07/16 SMI      */
+
+/*
+ * svc_auth.h, Service side of rpc authentication.
+ * 
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+/*
+ * Server side authenticator
+ */
+extern enum auth_stat _authenticate();
diff --git a/TBBT/trace_play/rpc/svc_auth_unix.c b/TBBT/trace_play/rpc/svc_auth_unix.c
new file mode 100755 (executable)
index 0000000..83ed327
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef lint
+static char sfs_svc_auth_unix_id[] = "@(#)svc_auth_unix.c     2.1     97/10/23";
+#endif
+/* @(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC; from 1.28 88/02/08 SMI */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Manassas, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_auth_unix.c
+ * Handles UNIX flavor authentication parameters on the service side of rpc.
+ * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
+ * _svcauth_unix does full blown unix style uid,gid+gids auth,
+ * _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
+ * Note: the shorthand has been gutted for efficiency.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc/rpc.h"
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+_svcauth_unix(
+       struct svc_req *rqst,
+       struct rpc_msg *msg)
+{
+       enum auth_stat stat;
+       XDR xdrs;
+       struct authunix_parms *aup;
+       int32_t *buf;
+       struct area {
+               struct authunix_parms area_aup;
+               char area_machname[MAX_MACHINE_NAME+1];
+               int area_gids[NGRPS];
+       } *area;
+       uint_t auth_len;
+       int str_len, gid_len;
+       int i;
+
+       area = (struct area *) rqst->rq_clntcred;
+       aup = &area->area_aup;
+       aup->aup_machname = area->area_machname;
+       aup->aup_gids = area->area_gids;
+       auth_len = (uint_t)msg->rm_call.cb_cred.oa_length;
+       xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
+       buf = XDR_INLINE(&xdrs, auth_len);
+       if (buf != NULL) {
+               aup->aup_time = IXDR_GET_LONG(buf);
+               str_len = IXDR_GET_U_LONG(buf);
+               if (str_len > MAX_MACHINE_NAME) {
+                       stat = AUTH_BADCRED;
+                       goto done;
+               }
+               memmove(aup->aup_machname, (void *)buf, (uint_t)str_len);
+               aup->aup_machname[str_len] = 0;
+               str_len = RNDUP(str_len);
+               buf += str_len / sizeof (int32_t);
+               aup->aup_uid = IXDR_GET_LONG(buf);
+               aup->aup_gid = IXDR_GET_LONG(buf);
+               gid_len = IXDR_GET_U_LONG(buf);
+               if (gid_len > NGRPS) {
+                       stat = AUTH_BADCRED;
+                       goto done;
+               }
+               aup->aup_len = gid_len;
+               for (i = 0; i < gid_len; i++) {
+                       aup->aup_gids[i] = IXDR_GET_LONG(buf);
+               }
+               /*
+                * five is the smallest unix credentials structure -
+                * timestamp, hostname len (0), uid, gid, and gids len (0).
+                */
+               if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
+                       (void) printf("bad auth_len gid %d str %d auth %d\n",
+                           gid_len, str_len, auth_len);
+                       stat = AUTH_BADCRED;
+                       goto done;
+               }
+       } else if (! xdr_authunix_parms(&xdrs, aup)) {
+               xdrs.x_op = XDR_FREE;
+               (void)xdr_authunix_parms(&xdrs, aup);
+               stat = AUTH_BADCRED;
+               goto done;
+       }
+       rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
+       rqst->rq_xprt->xp_verf.oa_length = 0;
+       stat = AUTH_OK;
+done:
+       XDR_DESTROY(&xdrs);
+       return (stat);
+}
+
+
+/*
+ * Shorthand unix authenticator
+ * Looks up longhand in a cache.
+ */
+/*ARGSUSED*/
+enum auth_stat 
+_svcauth_short(
+       struct svc_req *rqst,
+       struct rpc_msg *msg)
+{
+       return (AUTH_REJECTEDCRED);
+}
diff --git a/TBBT/trace_play/rpc/svc_raw.c b/TBBT/trace_play/rpc/svc_raw.c
new file mode 100755 (executable)
index 0000000..4b85782
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef lint
+static char sfs_svc_raw_id[] = "@(#)svc_raw.c     2.1     97/10/23";
+#endif
+/* @(#)svc_raw.c       2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_raw.c,   This a toy for simple testing and timing.
+ * Interface to create an rpc client and server in the same UNIX process.
+ * This lets us similate rpc and get rpc (round trip) overhead, without
+ * any interference from the kernal.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "rpc/rpc.h"
+
+
+/*
+ * This is the "network" that we will be moving data over
+ */
+static struct svcraw_private {
+       char    _raw_buf[UDPMSGSIZE];
+       SVCXPRT server;
+       XDR     xdr_stream;
+       char    verf_body[MAX_AUTH_BYTES];
+} *svcraw_private;
+
+static bool_t          svcraw_recv(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat  svcraw_stat(SVCXPRT *);
+static bool_t          svcraw_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t          svcraw_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t          svcraw_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void            svcraw_destroy(SVCXPRT *);
+
+static struct xp_ops server_ops = {
+       svcraw_recv,
+       svcraw_stat,
+       svcraw_getargs,
+       svcraw_reply,
+       svcraw_freeargs,
+       svcraw_destroy
+};
+
+SVCXPRT *
+svcraw_create(void)
+{
+       struct svcraw_private *srp = svcraw_private;
+
+       if (srp == 0) {
+               srp = (struct svcraw_private *)calloc(1, sizeof (struct svcraw_private));
+               if (srp == 0)
+                       return (0);
+       }
+       srp->server.xp_sock = 0;
+       srp->server.xp_port = 0;
+       srp->server.xp_ops = &server_ops;
+       srp->server.xp_verf.oa_base = srp->verf_body;
+       xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+       return (&srp->server);
+}
+
+/* ARGSUSED */
+static enum xprt_stat
+svcraw_stat(SVCXPRT *x)
+{
+
+       return (XPRT_IDLE);
+}
+
+/* ARGSUSED */
+static bool_t
+svcraw_recv(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       struct svcraw_private *srp = svcraw_private;
+       XDR *xdrs;
+
+       if (srp == 0)
+               return (0);
+       xdrs = &srp->xdr_stream;
+       xdrs->x_op = XDR_DECODE;
+       XDR_SETPOS(xdrs, 0);
+       if (! xdr_callmsg(xdrs, msg))
+              return (FALSE);
+       return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+svcraw_reply(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       struct svcraw_private *srp = svcraw_private;
+       XDR *xdrs;
+
+       if (srp == 0)
+               return (FALSE);
+       xdrs = &srp->xdr_stream;
+       xdrs->x_op = XDR_ENCODE;
+       XDR_SETPOS(xdrs, 0);
+       if (! xdr_replymsg(xdrs, msg))
+              return (FALSE);
+       (void)XDR_GETPOS(xdrs);  /* called just for overhead */
+       return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+svcraw_getargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void *args_ptr)
+{
+       struct svcraw_private *srp = svcraw_private;
+
+       if (srp == 0)
+               return (FALSE);
+       return ((*xdr_args)(&srp->xdr_stream, args_ptr));
+}
+
+/* ARGSUSED */
+static bool_t
+svcraw_freeargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void *args_ptr)
+{ 
+       struct svcraw_private *srp = svcraw_private;
+       XDR *xdrs;
+
+       if (srp == 0)
+               return (FALSE);
+       xdrs = &srp->xdr_stream;
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_args)(xdrs, args_ptr));
+} 
+
+/* ARGSUSED */
+static void
+svcraw_destroy(SVCXPRT *x)
+{
+}
diff --git a/TBBT/trace_play/rpc/svc_run.c b/TBBT/trace_play/rpc/svc_run.c
new file mode 100755 (executable)
index 0000000..0c787b4
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef lint
+static char sfs_svc_run_id[] = "@(#)svc_run.c     2.1     97/10/23";
+#endif
+/* @(#)svc_run.c       2.1 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * This is the rpc server side idle loop
+ * Wait for input, call server program.
+ */
+#include "rpc/rpc.h"
+#include <errno.h>
+
+void
+svc_run(void)
+{
+#ifdef FD_SETSIZE
+       fd_set readfds;
+#else
+       int readfds;
+#endif /* def FD_SETSIZE */
+       extern int errno;
+
+       for (;;) {
+#ifdef FD_SETSIZE
+               readfds = svc_fdset;
+#else
+               readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+               switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
+                              NULL)) {
+               case -1:
+                       if (errno == EINTR) {
+                               continue;
+                       }
+                       perror("svc_run: - select failed");
+                       return;
+               case 0:
+                       continue;
+               default:
+                       svc_getreqset(&readfds);
+               }
+       }
+}
diff --git a/TBBT/trace_play/rpc/svc_simple.c b/TBBT/trace_play/rpc/svc_simple.c
new file mode 100755 (executable)
index 0000000..ec22a47
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef lint
+static char sfs_svc_simple_id[] = "@(#)svc_simple.c     2.1     97/10/23";
+#endif
+/* @(#)svc_simple.c    2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/* 
+ * svc_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <netdb.h>
+
+static struct proglst {
+       char *(*p_progname)();
+       int  p_prognum;
+       int  p_procnum;
+       xdrproc_t p_inproc, p_outproc;
+       struct proglst *p_nxt;
+} *proglst;
+static void universal(struct svc_req *, SVCXPRT *);
+static SVCXPRT *transp;
+
+registerrpc(
+       int prognum,
+       int versnum,
+       int procnum,
+       char *(*progname)(),
+       xdrproc_t inproc,
+       xdrproc_t outproc)
+{
+       struct proglst *pl;
+       
+       if (procnum == NULLPROC) {
+               (void) fprintf(stderr,
+                   "can't reassign procedure number %d\n", NULLPROC);
+               return (-1);
+       }
+       if (transp == 0) {
+               transp = svcudp_create(RPC_ANYSOCK);
+               if (transp == NULL) {
+                       (void) fprintf(stderr, "couldn't create an rpc server\n");
+                       return (-1);
+               }
+       }
+       (void) pmap_unset((uint32_t)prognum, (uint32_t)versnum);
+       if (!svc_register(transp, (uint32_t)prognum, (uint32_t)versnum, 
+           universal, IPPROTO_UDP)) {
+               (void) fprintf(stderr, "couldn't register prog %d vers %d\n",
+                   prognum, versnum);
+               return (-1);
+       }
+       pl = (struct proglst *)malloc(sizeof(struct proglst));
+       if (pl == NULL) {
+               (void) fprintf(stderr, "registerrpc: out of memory\n");
+               return (-1);
+       }
+       pl->p_progname = progname;
+       pl->p_prognum = prognum;
+       pl->p_procnum = procnum;
+       pl->p_inproc = inproc;
+       pl->p_outproc = outproc;
+       pl->p_nxt = proglst;
+       proglst = pl;
+       return (0);
+}
+
+static void
+universal(
+       struct svc_req *rqstp,
+       SVCXPRT *transp)
+{
+       int prog, proc;
+       char *outdata;
+       char xdrbuf[UDPMSGSIZE];
+       struct proglst *pl;
+
+       /* 
+        * enforce "procnum 0 is echo" convention
+        */
+       if (rqstp->rq_proc == NULLPROC) {
+               if (svc_sendreply(transp, xdr_void, (char *)NULL) == FALSE) {
+                       (void) fprintf(stderr, "xxx\n");
+                       exit(1);
+               }
+               return;
+       }
+       prog = rqstp->rq_prog;
+       proc = rqstp->rq_proc;
+       for (pl = proglst; pl != NULL; pl = pl->p_nxt)
+               if (pl->p_prognum == prog && pl->p_procnum == proc) {
+                       /* decode arguments into a CLEAN buffer */
+                       memset(xdrbuf, '\0', sizeof(xdrbuf)); /* required ! */
+                       if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
+                               svcerr_decode(transp);
+                               return;
+                       }
+                       outdata = (*(pl->p_progname))(xdrbuf);
+                       if (outdata == NULL && pl->p_outproc != xdr_void)
+                               /* there was an error */
+                               return;
+                       if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
+                               (void) fprintf(stderr,
+                                   "trouble replying to prog %d\n",
+                                   pl->p_prognum);
+                               exit(1);
+                       }
+                       /* free the decoded arguments */
+                       (void)svc_freeargs(transp, pl->p_inproc, xdrbuf);
+                       return;
+               }
+       (void) fprintf(stderr, "never registered prog %d\n", prog);
+       exit(1);
+}
+
diff --git a/TBBT/trace_play/rpc/svc_tcp.c b/TBBT/trace_play/rpc/svc_tcp.c
new file mode 100755 (executable)
index 0000000..2b8b71a
--- /dev/null
@@ -0,0 +1,481 @@
+#ifndef lint
+static char sfs_svc_tcp_id[] = "@(#)svc_tcp.c     2.1     97/10/23";
+#endif
+/* @(#)svc_tcp.c       2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_tcp.c, Server side for TCP/IP based RPC. 
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Actually implements two flavors of transporter -
+ * a tcp rendezvouser (a listner and connection establisher)
+ * and a record/tcp stream.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <errno.h>
+
+/*
+ * Ops vector for TCP/IP based rpc service handle
+ */
+static bool_t          svctcp_recv(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat  svctcp_stat(SVCXPRT *);
+static bool_t          svctcp_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t          svctcp_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t          svctcp_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void            svctcp_destroy(SVCXPRT *);
+static bool_t          svctcp_abortrop(SVCXPRT *, struct rpc_msg *);
+static bool_t          svctcp_abortgop(SVCXPRT *, xdrproc_t, void *);
+
+static struct xp_ops svctcp_op = {
+       svctcp_recv,
+       svctcp_stat,
+       svctcp_getargs,
+       svctcp_reply,
+       svctcp_freeargs,
+       svctcp_destroy
+};
+
+/*
+ * Ops vector for TCP/IP rendezvous handler
+ */
+static bool_t          rendezvous_request(SVCXPRT *xprt, struct rpc_msg *);
+static enum xprt_stat  rendezvous_stat(SVCXPRT *);
+
+static struct xp_ops svctcp_rendezvous_op = {
+       rendezvous_request,
+       rendezvous_stat,
+       svctcp_abortgop,
+       svctcp_abortrop,
+       svctcp_abortgop,
+       svctcp_destroy
+};
+
+static int readtcp(), writetcp();
+static int readtcp(SVCXPRT *, char *, int);
+static int writetcp(SVCXPRT *, char *, int);
+static SVCXPRT *makefd_xprt(int, uint_t, uint_t);
+
+struct tcp_rendezvous { /* kept in xprt->xp_p1 */
+       uint_t sendsize;
+       uint_t recvsize;
+};
+
+struct tcp_conn {  /* kept in xprt->xp_p1 */
+       enum xprt_stat strm_stat;
+       uint32_t x_id;
+       XDR xdrs;
+       char verf_body[MAX_AUTH_BYTES];
+};
+
+/*
+ * Usage:
+ *     xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) tcp based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register).  This routine returns
+ * a NULL if a problem occurred.
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svctcp_create
+ * binds it to an arbitrary port.  The routine then starts a tcp
+ * listener on the socket's associated port.  In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ *
+ * Since tcp streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svctcp_create(
+       int sock,
+       uint_t sendsize,
+       uint_t recvsize)
+{
+       bool_t madesock = FALSE;
+       SVCXPRT *xprt;
+       struct tcp_rendezvous *r;
+       struct sockaddr_in addr;
+#if defined(AIX) 
+       size_t len;
+#else 
+       int len;
+#endif /* AIX */ 
+       len = sizeof(struct sockaddr_in);
+
+       if (sock == RPC_ANYSOCK) {
+               if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+                       perror("svctcp_.c - udp socket creation problem");
+                       return ((SVCXPRT *)NULL);
+               }
+               madesock = TRUE;
+       }
+       memset((char *)&addr, '\0', sizeof (addr));
+       addr.sin_family = AF_INET;
+       if (bindresvport(sock, &addr)) {
+               addr.sin_port = 0;
+               (void)bind(sock, (struct sockaddr *)&addr, len);
+       }
+       if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
+           (listen(sock, 2) != 0)) {
+               perror("svctcp_.c - cannot getsockname or listen");
+               if (madesock)
+                      (void)close(sock);
+               return ((SVCXPRT *)NULL);
+       }
+       r = (struct tcp_rendezvous *)mem_alloc(sizeof(struct tcp_rendezvous));
+       if (r == NULL) {
+               (void) fprintf(stderr, "svctcp_create: out of memory\n");
+               return (NULL);
+       }
+       r->sendsize = sendsize;
+       r->recvsize = recvsize;
+       xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+       if (xprt == NULL) {
+               (void) fprintf(stderr, "svctcp_create: out of memory\n");
+               return (NULL);
+       }
+       xprt->xp_p2 = NULL;
+       xprt->xp_p1 = (void *)r;
+       xprt->xp_verf = _null_auth;
+       xprt->xp_ops = &svctcp_rendezvous_op;
+       xprt->xp_port = ntohs(addr.sin_port);
+       xprt->xp_sock = sock;
+       xprt_register(xprt);
+       return (xprt);
+}
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svcfd_create(
+       int fd,
+       uint_t sendsize,
+       uint_t recvsize)
+{
+
+       return (makefd_xprt(fd, sendsize, recvsize));
+}
+
+static SVCXPRT *
+makefd_xprt(
+       int fd,
+       uint_t sendsize,
+       uint_t recvsize)
+{
+       SVCXPRT *xprt;
+       struct tcp_conn *cd;
+       xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+       if (xprt == (SVCXPRT *)NULL) {
+               (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
+               goto done;
+       }
+       cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
+       if (cd == (struct tcp_conn *)NULL) {
+               (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
+               mem_free((char *) xprt, sizeof(SVCXPRT));
+               xprt = (SVCXPRT *)NULL;
+               goto done;
+       }
+       cd->strm_stat = XPRT_IDLE;
+       xdrrec_create(&(cd->xdrs), sendsize, recvsize,
+           (void *)xprt, readtcp, writetcp);
+       xprt->xp_p2 = NULL;
+       xprt->xp_p1 = (void *)cd;
+       xprt->xp_verf.oa_base = cd->verf_body;
+       xprt->xp_addrlen = 0;
+       xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
+       xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
+       xprt->xp_sock = fd;
+       xprt_register(xprt);
+    done:
+       return (xprt);
+}
+
+/* ARGSUSED */
+static bool_t
+rendezvous_request(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       int sock;
+       struct tcp_rendezvous *r;
+       struct sockaddr_in addr;
+#if defined(AIX) 
+        size_t len;
+#else 
+        int len;
+#endif /* AIX */ 
+       r = (struct tcp_rendezvous *)xprt->xp_p1;
+    again:
+       len = sizeof(struct sockaddr_in);
+       if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
+           &len)) < 0) {
+               if (errno == EINTR)
+                       goto again;
+              return (FALSE);
+       }
+       /*
+        * make a new transporter (re-uses xprt)
+        */
+       xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
+       xprt->xp_raddr = addr;
+       xprt->xp_addrlen = len;
+       return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+/* ARGSUSED */
+static enum xprt_stat
+rendezvous_stat(SVCXPRT *x)
+{
+
+       return (XPRT_IDLE);
+}
+
+static void
+svctcp_destroy(
+       SVCXPRT *xprt)
+{
+       struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
+
+       xprt_unregister(xprt);
+       (void)close(xprt->xp_sock);
+       if (xprt->xp_port != 0) {
+               /* a rendezvouser socket */
+               xprt->xp_port = 0;
+       } else {
+               /* an actual connection socket */
+               XDR_DESTROY(&(cd->xdrs));
+       }
+       mem_free((void *)cd, sizeof(struct tcp_conn));
+       mem_free((void *)xprt, sizeof(SVCXPRT));
+}
+
+/*
+ * All read operations timeout after 35 seconds.
+ * A timeout is fatal for the connection.
+ */
+static struct timeval wait_per_try = { 35, 0 };
+
+/*
+ * reads data from the tcp conection.
+ * any error is fatal and the connection is closed.
+ * (And a read of zero bytes is a half closed stream => error.)
+ */
+static int
+readtcp(
+       SVCXPRT *xprt,
+       char *buf,
+       int len)
+{
+       int sock = xprt->xp_sock;
+#ifdef FD_SETSIZE
+       fd_set mask;
+       fd_set readfds;
+
+       FD_ZERO(&mask);
+       FD_SET(sock, &mask);
+#else
+       int mask = 1 << sock;
+       int readfds;
+#endif /* def FD_SETSIZE */
+       do {
+               readfds = mask;
+               if (select(_rpc_dtablesize(), &readfds, NULL, NULL, 
+                          &wait_per_try) <= 0) {
+                       if (errno == EINTR) {
+                               continue;
+                       }
+                       goto fatal_err;
+               }
+#ifdef FD_SETSIZE
+       } while (!FD_ISSET(sock, &readfds));
+#else
+       } while (readfds != mask);
+#endif /* def FD_SETSIZE */
+       if ((len = read(sock, buf, len)) > 0) {
+               return (len);
+       }
+fatal_err:
+       ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
+       return (-1);
+}
+
+/*
+ * writes data to the tcp connection.
+ * Any error is fatal and the connection is closed.
+ */
+static int
+writetcp(
+       SVCXPRT *xprt,
+       char *buf,
+       int len)
+{
+       int i, cnt;
+
+       for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+               if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
+                       ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
+                           XPRT_DIED;
+                       return (-1);
+               }
+       }
+       return (len);
+}
+
+static enum xprt_stat
+svctcp_stat(
+       SVCXPRT *xprt)
+{
+       struct tcp_conn *cd =
+           (struct tcp_conn *)(xprt->xp_p1);
+
+       if (cd->strm_stat == XPRT_DIED)
+               return (XPRT_DIED);
+       if (! xdrrec_eof(&(cd->xdrs)))
+               return (XPRT_MOREREQS);
+       return (XPRT_IDLE);
+}
+
+static bool_t
+svctcp_recv(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       struct tcp_conn *cd =
+           (struct tcp_conn *)(xprt->xp_p1);
+       XDR *xdrs = &(cd->xdrs);
+
+       xdrs->x_op = XDR_DECODE;
+       (void)xdrrec_skiprecord(xdrs);
+       if (xdr_callmsg(xdrs, msg)) {
+               cd->x_id = msg->rm_xid;
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+static bool_t
+svctcp_getargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void * args_ptr)
+{
+
+       return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
+}
+
+static bool_t
+svctcp_freeargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void * args_ptr)
+{
+       XDR *xdrs =
+           &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_args)(xdrs, args_ptr));
+}
+
+static bool_t
+svctcp_reply(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       struct tcp_conn *cd =
+           (struct tcp_conn *)(xprt->xp_p1);
+       XDR *xdrs = &(cd->xdrs);
+       bool_t stat;
+
+       xdrs->x_op = XDR_ENCODE;
+       msg->rm_xid = cd->x_id;
+       stat = xdr_replymsg(xdrs, msg);
+       (void)xdrrec_endofrecord(xdrs, TRUE);
+       return (stat);
+}
+
+/* ARGSUSED */
+static bool_t
+svctcp_abortrop(
+       SVCXPRT *x,
+       struct rpc_msg *msg)
+{
+       abort();
+       /* NOTREACHED */
+       return (FALSE);
+}
+
+/* ARGSUSED */
+static bool_t
+svctcp_abortgop(
+       SVCXPRT *x,
+       xdrproc_t argp,
+       void *arg)
+{
+       abort();
+       /* NOTREACHED */
+       return (FALSE);
+}
diff --git a/TBBT/trace_play/rpc/svc_udp.c b/TBBT/trace_play/rpc/svc_udp.c
new file mode 100755 (executable)
index 0000000..0a801b2
--- /dev/null
@@ -0,0 +1,507 @@
+#ifndef lint
+static char sfs_svc_udp_id[] = "@(#)svc_udp.c     2.1     97/10/23";
+#endif
+/* @(#)svc_udp.c       2.2 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_udp.c,
+ * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
+ * achieving execute-at-most-once semantics.)
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/rpc.h"
+#include "rpc/osdep.h"
+#include <errno.h>
+
+
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+
+static bool_t          svcudp_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t          svcudp_reply(SVCXPRT *, struct rpc_msg *) ;
+static enum xprt_stat  svcudp_stat(SVCXPRT *);
+static bool_t          svcudp_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t          svcudp_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void            svcudp_destroy(SVCXPRT *);
+
+static struct xp_ops svcudp_op = {
+       svcudp_recv,
+       svcudp_stat,
+       svcudp_getargs,
+       svcudp_reply,
+       svcudp_freeargs,
+       svcudp_destroy
+};
+
+/*
+ * kept in xprt->xp_p2
+ */
+struct svcudp_data {
+       uint_t   su_iosz;       /* byte size of send.recv buffer */
+       uint32_t su_xid;                /* transaction id */
+       XDR     su_xdrs;        /* XDR handle */
+       char    su_verfbody[MAX_AUTH_BYTES];    /* verifier body */
+       char *  su_cache;       /* cached data, NULL if no cache */
+};
+#define        su_data(xprt)   ((struct svcudp_data *)(xprt->xp_p2))
+
+static void cache_set(SVCXPRT *, uint32_t);
+static int cache_get(SVCXPRT *, struct rpc_msg *, char **, uint32_t *);
+
+/*
+ * Usage:
+ *     xprt = svcudp_create(sock);
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svcudp_create
+ * binds it to an arbitrary port.  In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ * Once *xprt is initialized, it is registered as a transporter;
+ * see (svc.h, xprt_register).
+ * The routines returns NULL if a problem occurred.
+ */
+SVCXPRT *
+svcudp_bufcreate(
+       int sock,
+       uint_t sendsz,
+       uint_t recvsz)
+{
+       bool_t madesock = FALSE;
+       SVCXPRT *xprt;
+       struct svcudp_data *su;
+       struct sockaddr_in addr;
+#if defined(AIX)
+       size_t len;
+#else
+       int len;
+#endif /* AIX */
+
+       len = sizeof(struct sockaddr_in);
+
+       if (sock == RPC_ANYSOCK) {
+               if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+                       perror("svcudp_create: socket creation problem");
+                       return ((SVCXPRT *)NULL);
+               }
+               madesock = TRUE;
+       }
+       memset((char *)&addr, '\0', sizeof (addr));
+       addr.sin_family = AF_INET;
+       if (bindresvport(sock, &addr)) {
+               addr.sin_port = 0;
+               (void)bind(sock, (struct sockaddr *)&addr, len);
+       }
+       if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
+               perror("svcudp_create - cannot getsockname");
+               if (madesock)
+                       (void)close(sock);
+               return ((SVCXPRT *)NULL);
+       }
+       xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+       if (xprt == NULL) {
+               (void)fprintf(stderr, "svcudp_create: out of memory\n");
+               return (NULL);
+       }
+       su = (struct svcudp_data *)mem_alloc(sizeof(struct svcudp_data));
+       if (su == NULL) {
+               (void)fprintf(stderr, "svcudp_create: out of memory\n");
+               return (NULL);
+       }
+       su->su_iosz = ((((sendsz > recvsz) ? sendsz : recvsz) + 3) / 4) * 4;
+       if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
+               (void)fprintf(stderr, "svcudp_create: out of memory\n");
+               return (NULL);
+       }
+       xdrmem_create(
+           &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
+       su->su_cache = NULL;
+       xprt->xp_p2 = (caddr_t)su;
+       xprt->xp_verf.oa_base = su->su_verfbody;
+       xprt->xp_ops = &svcudp_op;
+       xprt->xp_port = ntohs(addr.sin_port);
+       xprt->xp_sock = sock;
+       xprt_register(xprt);
+       return (xprt);
+}
+
+SVCXPRT *
+svcudp_create(
+       int sock)
+{
+
+       return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE));
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svcudp_stat(
+       SVCXPRT *xprt)
+{
+
+       return (XPRT_IDLE); 
+}
+
+static bool_t
+svcudp_recv(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg)
+{
+       struct svcudp_data *su = su_data(xprt);
+       XDR *xdrs = &(su->su_xdrs);
+       int rlen;
+       char *reply;
+       uint32_t replylen;
+
+    again:
+       xprt->xp_addrlen = sizeof(struct sockaddr_in);
+       rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
+           0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
+       if (rlen == -1 && errno == EINTR)
+               goto again;
+       if (rlen < 4*sizeof(uint32_t))
+               return (FALSE);
+       xdrs->x_op = XDR_DECODE;
+       XDR_SETPOS(xdrs, 0);
+       if (! xdr_callmsg(xdrs, msg))
+               return (FALSE);
+       su->su_xid = msg->rm_xid;
+       if (su->su_cache != NULL) {
+               if (cache_get(xprt, msg, &reply, &replylen)) {
+                       (void) sendto(xprt->xp_sock, reply, (int) replylen, 0,
+                         (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen);
+                       return (TRUE);
+               }
+       }
+       return (TRUE);
+}
+
+static bool_t
+svcudp_reply(
+       SVCXPRT *xprt, 
+       struct rpc_msg *msg) 
+{
+       struct svcudp_data *su = su_data(xprt);
+       XDR *xdrs = &(su->su_xdrs);
+       int slen;
+       bool_t stat = FALSE;
+
+       xdrs->x_op = XDR_ENCODE;
+       XDR_SETPOS(xdrs, 0);
+       msg->rm_xid = su->su_xid;
+       if (xdr_replymsg(xdrs, msg)) {
+               slen = (int)XDR_GETPOS(xdrs);
+               if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
+                   (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
+                   == slen) {
+                       stat = TRUE;
+                       if (su->su_cache && slen >= 0) {
+                               cache_set(xprt, (uint32_t) slen);
+                       }
+               }
+       }
+       return (stat);
+}
+
+static bool_t
+svcudp_getargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void *args_ptr)
+{
+
+       return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr));
+}
+
+static bool_t
+svcudp_freeargs(
+       SVCXPRT *xprt,
+       xdrproc_t xdr_args,
+       void *args_ptr)
+{
+       XDR *xdrs = &(su_data(xprt)->su_xdrs);
+
+       xdrs->x_op = XDR_FREE;
+       return ((*xdr_args)(xdrs, args_ptr));
+}
+
+static void
+svcudp_destroy(
+       SVCXPRT *xprt)
+{
+       struct svcudp_data *su = su_data(xprt);
+
+       xprt_unregister(xprt);
+       (void)close(xprt->xp_sock);
+       XDR_DESTROY(&(su->su_xdrs));
+       mem_free(rpc_buffer(xprt), su->su_iosz);
+       mem_free((caddr_t)su, sizeof(struct svcudp_data));
+       mem_free((caddr_t)xprt, sizeof(SVCXPRT));
+}
+
+
+/***********this could be a separate file*********************/
+
+/*
+ * Fifo cache for udp server
+ * Copies pointers to reply buffers into fifo cache
+ * Buffers are sent again if retransmissions are detected.
+ */
+
+#define SPARSENESS 4   /* 75% sparse */
+
+#define CACHE_PERROR(msg)      \
+       (void) fprintf(stderr,"%s\n", msg)
+
+#define ALLOC(type, size)      \
+       (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
+
+#define BZERO(addr, type, size)         \
+       memset((void *) addr, '\0', sizeof(type) * (int) (size)) 
+
+/*
+ * An entry in the cache
+ */
+typedef struct cache_node *cache_ptr;
+struct cache_node {
+       /*
+        * Index into cache is xid, proc, vers, prog and address
+        */
+       uint32_t cache_xid;
+       uint32_t cache_proc;
+       uint32_t cache_vers;
+       uint32_t cache_prog;
+       struct sockaddr_in cache_addr;
+       /*
+        * The cached reply and length
+        */
+       char * cache_reply;
+       uint32_t cache_replylen;
+       /*
+        * Next node on the list, if there is a collision
+        */
+       cache_ptr cache_next;   
+};
+
+
+
+/*
+ * The entire cache
+ */
+struct udp_cache {
+       uint32_t uc_size;               /* size of cache */
+       cache_ptr *uc_entries;  /* hash table of entries in cache */
+       cache_ptr *uc_fifo;     /* fifo list of entries in cache */
+       uint32_t uc_nextvictim; /* points to next victim in fifo list */
+       uint32_t uc_prog;               /* saved program number */
+       uint32_t uc_vers;               /* saved version number */
+       uint32_t uc_proc;               /* saved procedure number */
+       struct sockaddr_in uc_addr; /* saved caller's address */
+};
+
+
+/*
+ * the hashing function
+ */
+#define CACHE_LOC(transp, xid) \
+ (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))        
+
+
+/*
+ * Enable use of the cache. 
+ * Note: there is no disable.
+ */
+svcudp_enablecache(
+       SVCXPRT *transp,
+       uint32_t size)
+{
+       struct svcudp_data *su = su_data(transp);
+       struct udp_cache *uc;
+
+       if (su->su_cache != NULL) {
+               CACHE_PERROR("enablecache: cache already enabled");
+               return(0);      
+       }
+       uc = ALLOC(struct udp_cache, 1);
+       if (uc == NULL) {
+               CACHE_PERROR("enablecache: could not allocate cache");
+               return(0);
+       }
+       uc->uc_size = size;
+       uc->uc_nextvictim = 0;
+       uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
+       if (uc->uc_entries == NULL) {
+               CACHE_PERROR("enablecache: could not allocate cache data");
+               return(0);
+       }
+       BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
+       uc->uc_fifo = ALLOC(cache_ptr, size);
+       if (uc->uc_fifo == NULL) {
+               CACHE_PERROR("enablecache: could not allocate cache fifo");
+               return(0);
+       }
+       BZERO(uc->uc_fifo, cache_ptr, size);
+       su->su_cache = (char *) uc;
+       return(1);
+}
+
+
+/*
+ * Set an entry in the cache
+ */
+static void
+cache_set(
+       SVCXPRT *xprt,
+       uint32_t replylen)
+{
+       cache_ptr victim;       
+       cache_ptr *vicp;
+       struct svcudp_data *su = su_data(xprt);
+       struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+       uint_t loc;
+       char *newbuf;
+
+       /*
+        * Find space for the new entry, either by
+        * reusing an old entry, or by mallocing a new one
+        */
+       victim = uc->uc_fifo[uc->uc_nextvictim];
+       if (victim != NULL) {
+               loc = CACHE_LOC(xprt, victim->cache_xid);
+               for (vicp = &uc->uc_entries[loc]; 
+                 *vicp != NULL && *vicp != victim; 
+                 vicp = &(*vicp)->cache_next) 
+                               ;
+               if (*vicp == NULL) {
+                       CACHE_PERROR("cache_set: victim not found");
+                       return;
+               }
+               *vicp = victim->cache_next;     /* remote from cache */
+               newbuf = victim->cache_reply;
+       } else {
+               victim = ALLOC(struct cache_node, 1);
+               if (victim == NULL) {
+                       CACHE_PERROR("cache_set: victim alloc failed");
+                       return;
+               }
+               newbuf = mem_alloc(su->su_iosz);
+               if (newbuf == NULL) {
+                       CACHE_PERROR("cache_set: could not allocate new rpc_buffer");
+                       return;
+               }
+       }
+
+       /*
+        * Store it away
+        */
+       victim->cache_replylen = replylen;
+       victim->cache_reply = rpc_buffer(xprt);
+       rpc_buffer(xprt) = newbuf;
+       xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE);
+       victim->cache_xid = su->su_xid;
+       victim->cache_proc = uc->uc_proc;
+       victim->cache_vers = uc->uc_vers;
+       victim->cache_prog = uc->uc_prog;
+       victim->cache_addr = uc->uc_addr;
+       loc = CACHE_LOC(xprt, victim->cache_xid);
+       victim->cache_next = uc->uc_entries[loc];       
+       uc->uc_entries[loc] = victim;
+       uc->uc_fifo[uc->uc_nextvictim++] = victim;
+       uc->uc_nextvictim %= uc->uc_size;
+}
+
+/*
+ * Try to get an entry from the cache
+ * return 1 if found, 0 if not found
+ */
+static int
+cache_get(
+       SVCXPRT *xprt,
+       struct rpc_msg *msg,
+       char **replyp,
+       uint32_t *replylenp)
+{
+       uint_t loc;
+       cache_ptr ent;
+       struct svcudp_data *su = su_data(xprt);
+       struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+
+#      define EQADDR(a1, a2)   (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
+
+       loc = CACHE_LOC(xprt, su->su_xid);
+       for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
+               if (ent->cache_xid == su->su_xid &&
+                 ent->cache_proc == uc->uc_proc &&
+                 ent->cache_vers == uc->uc_vers &&
+                 ent->cache_prog == uc->uc_prog &&
+                 EQADDR(ent->cache_addr, uc->uc_addr)) {
+                       *replyp = ent->cache_reply;
+                       *replylenp = ent->cache_replylen;
+                       return(1);
+               }
+       }
+       /*
+        * Failed to find entry
+        * Remember a few things so we can do a set later
+        */
+       uc->uc_proc = msg->rm_call.cb_proc;
+       uc->uc_vers = msg->rm_call.cb_vers;
+       uc->uc_prog = msg->rm_call.cb_prog;
+       uc->uc_addr = xprt->xp_raddr;
+       return(0);
+}
+
diff --git a/TBBT/trace_play/rpc/types.h b/TBBT/trace_play/rpc/types.h
new file mode 100755 (executable)
index 0000000..0854cc6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * @(#)types.h     2.1     97/10/23
+ */
+/* @(#)types.h 2.3 88/08/15 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)types.h 1.18 87/07/24 SMI      */
+
+/*
+ * Rpc additions to <sys/types.h>
+ */
+#ifndef __TYPES_RPC_HEADER__
+#define __TYPES_RPC_HEADER__
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#if defined(__INTTYPES_INCLUDED) || defined(_SYS_INT_TYPES_H)
+#define HAVE_INTTYPES
+#endif
+
+#if defined(USE_INTTYPES)
+#include <inttypes.h>
+#else /* USE_INTTYPES */
+#if !defined(HAVE_INTTYPES)
+#define HAVE_INTTYPES
+
+typedef signed char            int8_t;
+typedef short                  int16_t;
+typedef int                    int32_t;
+
+typedef unsigned char           uint8_t;
+typedef unsigned short          uint16_t;
+typedef unsigned int            uint32_t;
+
+#endif /* !HAVE_INTTYPES */
+
+#endif /* USE_INTTYPES */
+
+#define        bool_t  int32_t
+#define        enum_t  int32_t
+#ifndef FALSE
+#define        FALSE   (0)
+#endif
+#ifndef TRUE
+#define        TRUE    (1)
+#endif
+#define __dontcare__   -1
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define mem_alloc(bsize)       malloc(bsize)
+#define mem_free(ptr, bsize)   free(ptr)
+
+#if defined(NO_T_TYPES)
+typedef unsigned int   uint_t;
+typedef unsigned char  uchar_t;
+#endif
+
+#ifdef notdef
+#ifndef INADDR_LOOPBACK
+#define       INADDR_LOOPBACK         (uint32_t)0x7F000001
+#endif
+#endif
+
+#endif /* ndef __TYPES_RPC_HEADER__ */
diff --git a/TBBT/trace_play/rpc/xdr.c b/TBBT/trace_play/rpc/xdr.c
new file mode 100755 (executable)
index 0000000..3a1fc88
--- /dev/null
@@ -0,0 +1,685 @@
+#ifndef lint
+static char sfs_xdr_c_id[] = "@(#)xdr.c     2.1     97/10/23";
+#endif
+/* @(#)xdr.c   2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr.c 1.35 87/08/12";
+#endif
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items.  See xdr.h for more info on the interface to
+ * xdr.
+ */
+#ifndef lint
+static char sfs_clnt_id[] = "@(#)xdr.c     2.1     97/10/23";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE      ((int32_t) 0)
+#define XDR_TRUE       ((int32_t) 1)
+#define LASTUNSIGNED   ((uint_t) 0-1)
+
+/*
+ * for unit alignment
+ */
+static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+/*
+ * Free a data structure using XDR
+ * Not a filter, but a convenient utility nonetheless
+ */
+void
+xdr_free(
+       xdrproc_t proc,
+       char *objp)
+{
+       XDR x;
+       
+       x.x_op = XDR_FREE;
+       (*proc)(&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void(void)
+{
+
+       return (TRUE);
+}
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(
+       XDR *xdrs,
+       int *ip)
+{
+
+#ifdef lint
+       (void) (xdr_int16_t(xdrs, (int16_t *)ip));
+       return (xdr_int32_t(xdrs, (int32_t *)ip));
+#else
+       if (sizeof (int) == sizeof (int32_t)) {
+               return (xdr_int32_t(xdrs, (int32_t *)ip));
+       } else {
+               return (xdr_int16_t(xdrs, (int16_t *)ip));
+       }
+#endif
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(
+       XDR *xdrs,
+       uint_t *up)
+{
+
+#ifdef lint
+       (void) (xdr_int16_t(xdrs, (int16_t *)up));
+       return (xdr_uint32_t(xdrs, (uint32_t *)up));
+#else
+       if (sizeof (uint_t) == sizeof (uint32_t)) {
+               return (xdr_uint32_t(xdrs, (uint32_t *)up));
+       } else {
+               return (xdr_int16_t(xdrs, (int16_t *)up));
+       }
+#endif
+}
+
+/*
+ * XDR long integers
+ * same as xdr_u_long - open coded to save a proc call!
+ */
+bool_t
+xdr_long(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       if (xdrs->x_op == XDR_ENCODE)
+               return (XDR_PUTLONG(xdrs, lp));
+
+       if (xdrs->x_op == XDR_DECODE)
+               return (XDR_GETLONG(xdrs, lp));
+
+       if (xdrs->x_op == XDR_FREE)
+               return (TRUE);
+
+       return (FALSE);
+}
+
+bool_t
+xdr_int32_t(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       if (xdrs->x_op == XDR_ENCODE)
+               return (XDR_PUTLONG(xdrs, lp));
+
+       if (xdrs->x_op == XDR_DECODE)
+               return (XDR_GETLONG(xdrs, lp));
+
+       if (xdrs->x_op == XDR_FREE)
+               return (TRUE);
+
+       return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ * same as xdr_long - open coded to save a proc call!
+ */
+bool_t
+xdr_u_long(
+       XDR *xdrs,
+       uint32_t *ulp)
+{
+
+       if (xdrs->x_op == XDR_DECODE)
+               return (XDR_GETLONG(xdrs, (int32_t *)ulp));
+       if (xdrs->x_op == XDR_ENCODE)
+               return (XDR_PUTLONG(xdrs, (int32_t *)ulp));
+       if (xdrs->x_op == XDR_FREE)
+               return (TRUE);
+       return (FALSE);
+}
+
+bool_t
+xdr_uint32_t(
+       XDR *xdrs,
+       uint32_t *ulp)
+{
+
+       if (xdrs->x_op == XDR_DECODE)
+               return (XDR_GETLONG(xdrs, (int32_t *)ulp));
+       if (xdrs->x_op == XDR_ENCODE)
+               return (XDR_PUTLONG(xdrs, (int32_t *)ulp));
+       if (xdrs->x_op == XDR_FREE)
+               return (TRUE);
+       return (FALSE);
+}
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(
+       XDR *xdrs,
+       int16_t *sp)
+{
+       int32_t l;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               l = (int32_t) *sp;
+               return (XDR_PUTLONG(xdrs, &l));
+
+       case XDR_DECODE:
+               if (!XDR_GETLONG(xdrs, &l)) {
+                       return (FALSE);
+               }
+               *sp = (int16_t) l;
+               return (TRUE);
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+bool_t
+xdr_int16_t(
+       XDR *xdrs,
+       int16_t *sp)
+{
+       int32_t l;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               l = (int32_t) *sp;
+               return (XDR_PUTLONG(xdrs, &l));
+
+       case XDR_DECODE:
+               if (!XDR_GETLONG(xdrs, &l)) {
+                       return (FALSE);
+               }
+               *sp = (int16_t) l;
+               return (TRUE);
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(
+       XDR *xdrs,
+       uint16_t *usp)
+{
+       uint32_t l;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               l = (uint32_t) *usp;
+               return (XDR_PUTLONG(xdrs, (int32_t *)&l));
+
+       case XDR_DECODE:
+               if (!XDR_GETLONG(xdrs, (int32_t *)&l)) {
+                       return (FALSE);
+               }
+               *usp = (uint16_t) l;
+               return (TRUE);
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+bool_t
+xdr_uint16_t(
+       XDR *xdrs,
+       uint16_t *usp)
+{
+       uint32_t l;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               l = (uint32_t) *usp;
+               return (XDR_PUTLONG(xdrs, (int32_t *)&l));
+
+       case XDR_DECODE:
+               if (!XDR_GETLONG(xdrs, (int32_t *)&l)) {
+                       return (FALSE);
+               }
+               *usp = (uint16_t) l;
+               return (TRUE);
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(
+       XDR *xdrs,
+       char *cp)
+{
+       int i;
+
+       i = (*cp);
+       if (!xdr_int(xdrs, &i)) {
+               return (FALSE);
+       }
+       *cp = i;
+       return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(
+       XDR *xdrs,
+       uchar_t *cp)
+{
+       uint_t u;
+
+       u = (*cp);
+       if (!xdr_u_int(xdrs, &u)) {
+               return (FALSE);
+       }
+       *cp = u;
+       return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(
+       XDR *xdrs,
+       bool_t *bp)
+{
+       int32_t lb;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               lb = *bp ? XDR_TRUE : XDR_FALSE;
+               return (XDR_PUTLONG(xdrs, &lb));
+
+       case XDR_DECODE:
+               if (!XDR_GETLONG(xdrs, &lb)) {
+                       return (FALSE);
+               }
+               *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+               return (TRUE);
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum(
+       XDR *xdrs,
+       enum_t *ep)
+{
+#ifndef lint
+       enum sizecheck { SIZEVAL };     /* used to find the size of an enum */
+
+       /*
+        * enums are treated as ints
+        */
+       if (sizeof (enum sizecheck) == sizeof (int32_t)) {
+               return (xdr_int32_t(xdrs, (int32_t *)ep));
+       } else if (sizeof (enum sizecheck) == sizeof (int16_t)) {
+               return (xdr_int16_t(xdrs, (int16_t *)ep));
+       } else {
+               return (FALSE);
+       }
+#else
+       (void) (xdr_int16_t(xdrs, (int16_t *)ep));
+       return (xdr_int32_t(xdrs, (int32_t *)ep));
+#endif
+}
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque(
+       XDR *xdrs,
+       void *cp,
+       uint_t cnt)
+{
+       uint_t rndup;
+       static crud[BYTES_PER_XDR_UNIT];
+
+       /*
+        * if no data we are done
+        */
+       if (cnt == 0)
+               return (TRUE);
+
+       /*
+        * round byte count to full xdr units
+        */
+       rndup = cnt % BYTES_PER_XDR_UNIT;
+       if (rndup > 0)
+               rndup = BYTES_PER_XDR_UNIT - rndup;
+
+       if (xdrs->x_op == XDR_DECODE) {
+               if (!XDR_GETBYTES(xdrs, cp, cnt)) {
+                       return (FALSE);
+               }
+               if (rndup == 0)
+                       return (TRUE);
+               return (XDR_GETBYTES(xdrs, crud, rndup));
+       }
+
+       if (xdrs->x_op == XDR_ENCODE) {
+               if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
+                       return (FALSE);
+               }
+               if (rndup == 0)
+                       return (TRUE);
+               return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
+       }
+
+       if (xdrs->x_op == XDR_FREE) {
+               return (TRUE);
+       }
+
+       return (FALSE);
+}
+
+/*
+ * XDR counted bytes
+ * *cpp is a pointer to the bytes, *sizep is the count.
+ * If *cpp is NULL maxsize bytes are allocated
+ */
+bool_t
+xdr_bytes(
+       XDR *xdrs,
+       char **cpp,
+       uint_t *sizep,
+       uint_t maxsize)
+{
+       char *sp = *cpp;  /* sp is the actual string pointer */
+       uint_t nodesize;
+
+       /*
+        * first deal with the length since xdr bytes are counted
+        */
+       if (! xdr_u_int(xdrs, sizep)) {
+               return (FALSE);
+       }
+       nodesize = *sizep;
+       if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
+               return (FALSE);
+       }
+
+       /*
+        * now deal with the actual bytes
+        */
+       switch (xdrs->x_op) {
+
+       case XDR_DECODE:
+               if (nodesize == 0) {
+                       return (TRUE);
+               }
+               if (sp == NULL) {
+                       *cpp = sp = (char *)mem_alloc(nodesize);
+               }
+               if (sp == NULL) {
+                       (void) fprintf(stderr, "xdr_bytes: out of memory\n");
+                       return (FALSE);
+               }
+               /* fall into ... */
+
+       case XDR_ENCODE:
+               return (xdr_opaque(xdrs, sp, nodesize));
+
+       case XDR_FREE:
+               if (sp != NULL) {
+                       mem_free(sp, nodesize);
+                       *cpp = NULL;
+               }
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/*
+ * Implemented here due to commonality of the object.
+ */
+bool_t
+xdr_netobj(
+       XDR *xdrs,
+       struct netobj *np)
+{
+
+       return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
+}
+
+/*
+ * XDR a descriminated union
+ * Support routine for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer.  The routine gets
+ * the discriminant value and then searches the array of xdrdiscrims
+ * looking for that value.  It calls the procedure given in the xdrdiscrim
+ * to handle the discriminant.  If there is no specific routine a default
+ * routine may be called.
+ * If there is no specific or default routine an error is returned.
+ */
+bool_t
+xdr_union(
+       XDR *xdrs,
+       enum_t *dscmp,          /* enum to decide which arm to work on */
+       char *unp,              /* the union itself */
+       struct xdr_discrim *choices,    /* [value, xdr proc] for each arm */
+       xdrproc_t dfault)       /* default xdr routine */
+{
+       enum_t dscm;
+
+       /*
+        * we deal with the discriminator;  it's an enum
+        */
+       if (! xdr_enum(xdrs, dscmp)) {
+               return (FALSE);
+       }
+       dscm = *dscmp;
+
+       /*
+        * search choices for a value that matches the discriminator.
+        * if we find one, execute the xdr routine for that value.
+        */
+       for (; choices->proc != NULL_xdrproc_t; choices++) {
+               if (choices->value == dscm)
+                       return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
+       }
+
+       /*
+        * no match - execute the default xdr routine if there is one
+        */
+       return ((dfault == NULL_xdrproc_t) ? FALSE :
+           (*dfault)(xdrs, unp, LASTUNSIGNED));
+}
+
+
+/*
+ * Non-portable xdr primitives.
+ * Care should be taken when moving these routines to new architectures.
+ */
+
+
+/*
+ * XDR null terminated ASCII strings
+ * xdr_string deals with "C strings" - arrays of bytes that are
+ * terminated by a NULL character.  The parameter cpp references a
+ * pointer to storage; If the pointer is null, then the necessary
+ * storage is allocated.  The last parameter is the max allowed length
+ * of the string as specified by a protocol.
+ */
+bool_t
+xdr_string(
+       XDR *xdrs,
+       char **cpp,
+       uint_t maxsize)
+{
+       char *sp = *cpp;  /* sp is the actual string pointer */
+       uint_t size;
+       uint_t nodesize;
+
+       /*
+        * first deal with the length since xdr strings are counted-strings
+        */
+       switch (xdrs->x_op) {
+       case XDR_FREE:
+               if (sp == NULL) {
+                       return(TRUE);   /* already free */
+               }
+               /* fall through... */
+       case XDR_ENCODE:
+               size = strlen(sp);
+               break;
+       }
+       if (! xdr_u_int(xdrs, &size)) {
+               return (FALSE);
+       }
+       if (size > maxsize) {
+               return (FALSE);
+       }
+       nodesize = size + 1;
+
+       /*
+        * now deal with the actual bytes
+        */
+       switch (xdrs->x_op) {
+
+       case XDR_DECODE:
+               if (nodesize == 0) {
+                       return (TRUE);
+               }
+               if (sp == NULL)
+                       *cpp = sp = (char *)mem_alloc(nodesize);
+               if (sp == NULL) {
+                       (void) fprintf(stderr, "xdr_string: out of memory\n");
+                       return (FALSE);
+               }
+               sp[size] = 0;
+               /* fall into ... */
+
+       case XDR_ENCODE:
+               return (xdr_opaque(xdrs, sp, size));
+
+       case XDR_FREE:
+               mem_free(sp, nodesize);
+               *cpp = NULL;
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/* 
+ * Wrapper for xdr_string that can be called directly from 
+ * routines like clnt_call
+ */
+bool_t
+xdr_wrapstring(
+       XDR *xdrs,
+       char **cpp)
+{
+       if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
+               return (TRUE);
+       }
+       return (FALSE);
+}
diff --git a/TBBT/trace_play/rpc/xdr.h b/TBBT/trace_play/rpc/xdr.h
new file mode 100755 (executable)
index 0000000..2ccc5d2
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * @(#)xdr.h     2.1     97/10/23
+ */
+
+/* @(#)xdr.h   2.2 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)xdr.h 1.19 87/04/22 SMI      */
+
+/*
+ * xdr.h, External Data Representation Serialization Routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef __XDR_HEADER__
+#define __XDR_HEADER__
+
+#include <stdio.h>
+
+/*
+ * XDR provides a conventional way for converting between C data
+ * types and an external bit-string representation.  Library supplied
+ * routines provide for the conversion on built-in C data types.  These
+ * routines and utility routines defined here are used to help implement
+ * a type encode/decode routine for each user-defined type.
+ *
+ * Each data type provides a single procedure which takes two arguments:
+ *
+ *     bool_t
+ *     xdrproc(xdrs, argresp)
+ *             XDR *xdrs;
+ *             <type> *argresp;
+ *
+ * xdrs is an instance of a XDR handle, to which or from which the data
+ * type is to be converted.  argresp is a pointer to the structure to be
+ * converted.  The XDR handle contains an operation field which indicates
+ * which of the operations (ENCODE, DECODE * or FREE) is to be performed.
+ *
+ * XDR_DECODE may allocate space if the pointer argresp is null.  This
+ * data can be freed with the XDR_FREE operation.
+ *
+ * We write only one procedure per data type to make it easy
+ * to keep the encode and decode procedures for a data type consistent.
+ * In many cases the same code performs all operations on a user defined type,
+ * because all the hard work is done in the component type routines.
+ * decode as a series of calls on the nested data types.
+ */
+
+/*
+ * Xdr operations.  XDR_ENCODE causes the type to be encoded into the
+ * stream.  XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+       XDR_ENCODE=0,
+       XDR_DECODE=1,
+       XDR_FREE=2
+};
+
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT     (4)
+#define RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
+                   * BYTES_PER_XDR_UNIT)
+
+/*
+ * A xdrproc_t exists for each data type which is to be encoded or decoded.
+ *
+ * The second argument to the xdrproc_t is a pointer to an opaque pointer.
+ * The opaque pointer generally points to a structure of the data type
+ * to be decoded.  If this pointer is 0, then the type routines should
+ * allocate dynamic storage of the appropriate size and return it.
+ * bool_t      (*xdrproc_t)(XDR *, void **);
+ */
+typedef        bool_t (*xdrproc_t)();
+
+/*
+ * The XDR handle.
+ * Contains operation which is being applied to the stream,
+ * an operations vector for the paticular implementation (e.g. see xdr_mem.c),
+ * and two private fields for the use of the particular impelementation.
+ */
+typedef struct {
+       enum xdr_op     x_op;           /* operation; fast additional param */
+       struct xdr_ops *x_ops;
+       char *          x_public;       /* users' data */
+       char *          x_private;      /* pointer to private data */
+       char *          x_base;         /* private used for position info */
+       int             x_handy;        /* extra private word */
+} XDR;
+
+struct xdr_ops {
+       /* get a long from underlying stream */
+       bool_t  (*x_getlong)(XDR *, int32_t *);
+       /* put a long to " */
+       bool_t  (*x_putlong)(XDR *, int32_t *);
+       /* get some bytes from " */
+       bool_t  (*x_getbytes)(XDR *, void *, uint_t);
+       /* put some bytes to " */
+       bool_t  (*x_putbytes)(XDR *, void *, uint_t);
+       /* returns bytes off from beginning */
+       uint_t  (*x_getpostn)(XDR *);
+       /* lets you reposition the stream */
+       bool_t  (*x_setpostn)(XDR *, uint_t);
+       /* buf quick ptr to buffered data */
+       int32_t *(*x_inline)(XDR *, uint_t);
+       /* free privates of this xdr_stream */
+       void    (*x_destroy)(XDR *);
+};
+
+/*
+ * Operations defined on a XDR handle
+ *
+ * XDR         *xdrs;
+ * int32_t     *longp;
+ * void *       addr;
+ * uint_t       len;
+ * uint_t       pos;
+ */
+#define XDR_GETLONG(xdrs, longp)                       \
+       (*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+#define xdr_getlong(xdrs, longp)                       \
+       (*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+
+#define XDR_PUTLONG(xdrs, longp)                       \
+       (*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+#define xdr_putlong(xdrs, longp)                       \
+       (*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+
+#define XDR_GETBYTES(xdrs, addr, len)                  \
+       (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+#define xdr_getbytes(xdrs, addr, len)                  \
+       (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+
+#define XDR_PUTBYTES(xdrs, addr, len)                  \
+       (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+#define xdr_putbytes(xdrs, addr, len)                  \
+       (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+
+#define XDR_GETPOS(xdrs)                               \
+       (*(xdrs)->x_ops->x_getpostn)(xdrs)
+#define xdr_getpos(xdrs)                               \
+       (*(xdrs)->x_ops->x_getpostn)(xdrs)
+
+#define XDR_SETPOS(xdrs, pos)                          \
+       (*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+#define xdr_setpos(xdrs, pos)                          \
+       (*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+
+#define        XDR_INLINE(xdrs, len)                           \
+       (*(xdrs)->x_ops->x_inline)(xdrs, len)
+#define        xdr_inline(xdrs, len)                           \
+       (*(xdrs)->x_ops->x_inline)(xdrs, len)
+
+#define        XDR_DESTROY(xdrs)                               \
+       if ((xdrs)->x_ops->x_destroy)                   \
+               (*(xdrs)->x_ops->x_destroy)(xdrs)
+#define        xdr_destroy(xdrs)                               \
+       if ((xdrs)->x_ops->x_destroy)                   \
+               (*(xdrs)->x_ops->x_destroy)(xdrs)
+
+/*
+ * Support struct for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * a entry with a null procedure pointer.  The xdr_union routine gets
+ * the discriminant value and then searches the array of structures
+ * for a matching value.  If a match is found the associated xdr routine
+ * is called to handle that part of the union.  If there is
+ * no match, then a default routine may be called.
+ * If there is no match and no default routine it is an error.
+ */
+#define NULL_xdrproc_t ((xdrproc_t)0)
+struct xdr_discrim {
+       int     value;
+       xdrproc_t proc;
+};
+
+/*
+ * In-line routines for fast encode/decode of primitve data types.
+ * Caveat emptor: these use single memory cycles to get the
+ * data from the underlying buffer, and will fail to operate
+ * properly if the data is not aligned.  The standard way to use these
+ * is to say:
+ *     if ((buf = XDR_INLINE(xdrs, count)) == NULL)
+ *             return (FALSE);
+ *     <<< macro calls >>>
+ * where ``count'' is the number of bytes of data occupied
+ * by the primitive data types.
+ *
+ * N.B. and frozen for all time: each data type here uses 4 bytes
+ * of external representation.
+ */
+#define IXDR_GET_LONG(buf)             ((int32_t)ntohl((uint32_t)*(buf)++))
+#define IXDR_PUT_LONG(buf, v)          (*(buf)++ = (int32_t)htonl((uint32_t)v))
+
+#define IXDR_GET_BOOL(buf)             ((bool_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_ENUM(buf, t)          ((t)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_LONG(buf)           ((uint32_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_SHORT(buf)            ((int16_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_SHORT(buf)          ((uint16_t)IXDR_GET_LONG(buf))
+
+#define IXDR_PUT_BOOL(buf, v)          IXDR_PUT_LONG((buf), ((int32_t)(v)))
+#define IXDR_PUT_ENUM(buf, v)          IXDR_PUT_LONG((buf), ((int32_t)(v)))
+#define IXDR_PUT_U_LONG(buf, v)                IXDR_PUT_LONG((buf), ((int32_t)(v)))
+#define IXDR_PUT_SHORT(buf, v)         IXDR_PUT_LONG((buf), ((int32_t)(v)))
+#define IXDR_PUT_U_SHORT(buf, v)       IXDR_PUT_LONG((buf), ((int32_t)(v)))
+
+/*
+ * These are the "generic" xdr routines.
+ */
+extern bool_t  xdr_void(void);
+extern bool_t  xdr_int(XDR *, int *);
+extern bool_t  xdr_u_int(XDR *, uint_t *);
+extern bool_t  xdr_long(XDR *, int32_t *);
+extern bool_t  xdr_u_long(XDR *, uint32_t *);
+extern bool_t  xdr_int32_t(XDR *, int32_t *);
+extern bool_t  xdr_uint32_t(XDR *, uint32_t *);
+extern bool_t  xdr_short(XDR *, int16_t *);
+extern bool_t  xdr_u_short(XDR *, uint16_t *);
+extern bool_t  xdr_int16_t(XDR *, int16_t *);
+extern bool_t  xdr_uint16_t(XDR *, uint16_t *);
+extern bool_t  xdr_bool(XDR *, bool_t *);
+extern bool_t  xdr_enum(XDR *, enum_t *);
+extern bool_t  xdr_array(XDR *, void **, uint_t *, uint_t, uint_t, xdrproc_t);
+extern bool_t  xdr_bytes(XDR *, char **cp, uint_t *, uint_t);
+extern bool_t  xdr_opaque(XDR *, void *, uint_t);
+extern bool_t  xdr_string(XDR *, char **cp, uint_t);
+extern bool_t  xdr_union(XDR *, enum_t *, char *, struct xdr_discrim *, xdrproc_t);
+extern bool_t  xdr_char(XDR *, char *);
+extern bool_t  xdr_u_char(XDR *, uchar_t *);
+extern bool_t  xdr_vector(XDR *, char *, uint_t, uint_t, xdrproc_t);
+extern bool_t  xdr_float(XDR *, float *);
+extern bool_t  xdr_double(XDR *, double *);
+extern bool_t  xdr_reference(XDR *, void **, uint_t, xdrproc_t);
+extern bool_t  xdr_pointer(XDR *, void **, uint_t, xdrproc_t);
+extern bool_t  xdr_wrapstring(XDR *, char **);
+
+/*
+ * Common opaque bytes objects used by many rpc protocols;
+ * declared here due to commonality.
+ */
+#define MAX_NETOBJ_SZ 1024 
+struct netobj {
+       uint_t  n_len;
+       char    *n_bytes;
+};
+typedef struct netobj netobj;
+extern bool_t   xdr_netobj(XDR *, netobj *);
+
+/*
+ * These are the public routines for the various implementations of
+ * xdr streams.
+ */
+extern void   xdrmem_create(XDR *, void *, uint_t, enum xdr_op);
+extern void   xdrstdio_create(XDR *, FILE *, enum xdr_op);
+extern void   xdrrec_create(XDR *, uint_t, uint_t, void *, int (*)(), int (*)());
+extern bool_t xdrrec_endofrecord(XDR *, bool_t);
+extern bool_t xdrrec_skiprecord(XDR *);
+extern bool_t xdrrec_eof(XDR *);
+
+#endif /* !__XDR_HEADER__ */
diff --git a/TBBT/trace_play/rpc/xdr_array.c b/TBBT/trace_play/rpc/xdr_array.c
new file mode 100755 (executable)
index 0000000..d448022
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef lint
+static char sfs_xdr_array_id[] = "@(#)xdr_array.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_array.c     2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_array.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * arrays.  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+
+#define LASTUNSIGNED   ((uint_t)0-1)
+
+
+/*
+ * XDR an array of arbitrary elements
+ * *addrp is a pointer to the array, *sizep is the number of elements.
+ * If addrp is NULL (*sizep * elsize) bytes are allocated.
+ * elsize is the size (in bytes) of each element, and elproc is the
+ * xdr procedure to call to handle each element of the array.
+ */
+bool_t
+xdr_array(
+       XDR *xdrs,
+       void **addrp,           /* array pointer */
+       uint_t *sizep,          /* number of elements */
+       uint_t maxsize,         /* max numberof elements */
+       uint_t elsize,          /* size in bytes of each element */
+       xdrproc_t elproc)       /* xdr routine to handle each element */
+{
+       uint_t i;
+       char * target = *addrp;
+       uint_t c;  /* the actual element count */
+       bool_t stat = TRUE;
+       uint_t nodesize;
+
+       /* like strings, arrays are really counted arrays */
+       if (! xdr_u_int(xdrs, sizep)) {
+               return (FALSE);
+       }
+       c = *sizep;
+       if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) {
+               return (FALSE);
+       }
+       nodesize = c * elsize;
+
+       /*
+        * if we are deserializing, we may need to allocate an array.
+        * We also save time by checking for a null array if we are freeing.
+        */
+       if (target == NULL)
+               switch (xdrs->x_op) {
+               case XDR_DECODE:
+                       if (c == 0)
+                               return (TRUE);
+                       *addrp = target = mem_alloc(nodesize);
+                       if (target == NULL) {
+                               (void) fprintf(stderr, 
+                                       "xdr_array: out of memory\n");
+                               return (FALSE);
+                       }
+                       memset(target, '\0', nodesize);
+                       break;
+
+               case XDR_FREE:
+                       return (TRUE);
+       }
+       
+       /*
+        * now we xdr each element of array
+        */
+       for (i = 0; (i < c) && stat; i++) {
+               stat = (*elproc)(xdrs, target, LASTUNSIGNED);
+               target += elsize;
+       }
+
+       /*
+        * the array may need freeing
+        */
+       if (xdrs->x_op == XDR_FREE) {
+               mem_free(*addrp, nodesize);
+               *addrp = NULL;
+       }
+       return (stat);
+}
+
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(
+       XDR *xdrs,
+       char *basep,
+       uint_t nelem,
+       uint_t elemsize,
+       xdrproc_t xdr_elem)     
+{
+       uint_t i;
+       char *elptr;
+
+       elptr = basep;
+       for (i = 0; i < nelem; i++) {
+               if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) {
+                       return(FALSE);
+               }
+               elptr += elemsize;
+       }
+       return(TRUE);   
+}
+
diff --git a/TBBT/trace_play/rpc/xdr_float.c b/TBBT/trace_play/rpc/xdr_float.c
new file mode 100755 (executable)
index 0000000..9048665
--- /dev/null
@@ -0,0 +1,288 @@
+#ifndef lint
+static char sfs_xdr_float_id[] = "@(#)xdr_float.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_float.c     2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_float.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "floating point" xdr routines used to (de)serialize
+ * most common data items.  See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include <stdio.h>
+
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+
+/*
+ * NB: Not portable.
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+
+#ifdef vax
+
+/* What IEEE single precision floating point looks like on a Vax */
+struct ieee_single {
+       unsigned int    mantissa: 23;
+       unsigned int    exp     : 8;
+       unsigned int    sign    : 1;
+};
+
+/* Vax single precision floating point */
+struct vax_single {
+       unsigned int    mantissa1 : 7;
+       unsigned int    exp       : 8;
+       unsigned int    sign      : 1;
+       unsigned int    mantissa2 : 16;
+};
+
+#define VAX_SNG_BIAS   0x81
+#define IEEE_SNG_BIAS  0x7f
+
+static struct sgl_limits {
+       struct vax_single s;
+       struct ieee_single ieee;
+} sgl_limits[2] = {
+       {{ 0x7f, 0xff, 0x0, 0xffff },   /* Max Vax */
+       { 0x0, 0xff, 0x0 }},            /* Max IEEE */
+       {{ 0x0, 0x0, 0x0, 0x0 },        /* Min Vax */
+       { 0x0, 0x0, 0x0 }}              /* Min IEEE */
+};
+#endif /* vax */
+
+bool_t
+xdr_float(xdrs, fp)
+       register XDR *xdrs;
+       register float *fp;
+{
+#if defined(vax)
+       struct ieee_single is;
+       struct vax_single vs, *vsp;
+       struct sgl_limits *lim;
+       int i;
+#endif
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+#if !defined(vax)
+               return (XDR_PUTLONG(xdrs, (int32_t *)fp));
+#else
+               vs = *((struct vax_single *)fp);
+               for (i = 0, lim = sgl_limits;
+                       i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+                       i++, lim++) {
+                       if ((vs.mantissa2 == lim->s.mantissa2) &&
+                               (vs.exp == lim->s.exp) &&
+                               (vs.mantissa1 == lim->s.mantissa1)) {
+                               is = lim->ieee;
+                               goto shipit;
+                       }
+               }
+               is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
+               is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
+       shipit:
+               is.sign = vs.sign;
+               return (XDR_PUTLONG(xdrs, (int32_t *)&is));
+#endif
+
+       case XDR_DECODE:
+#if !defined(vax)
+               return (XDR_GETLONG(xdrs, (int32_t *)fp));
+#else
+               vsp = (struct vax_single *)fp;
+               if (!XDR_GETLONG(xdrs, (int32_t *)&is))
+                       return (FALSE);
+               for (i = 0, lim = sgl_limits;
+                       i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+                       i++, lim++) {
+                       if ((is.exp == lim->ieee.exp) &&
+                               (is.mantissa == lim->ieee.mantissa)) {
+                               *vsp = lim->s;
+                               goto doneit;
+                       }
+               }
+               vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
+               vsp->mantissa2 = is.mantissa;
+               vsp->mantissa1 = (is.mantissa >> 16);
+       doneit:
+               vsp->sign = is.sign;
+               return (TRUE);
+#endif
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/*
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+
+#ifdef vax
+/* What IEEE double precision floating point looks like on a Vax */
+struct ieee_double {
+       unsigned int    mantissa1 : 20;
+       unsigned int    exp       : 11;
+       unsigned int    sign      : 1;
+       unsigned int    mantissa2 : 32;
+};
+
+/* Vax double precision floating point */
+struct  vax_double {
+       unsigned int    mantissa1 : 7;
+       unsigned int    exp       : 8;
+       unsigned int    sign      : 1;
+       unsigned int    mantissa2 : 16;
+       unsigned int    mantissa3 : 16;
+       unsigned int    mantissa4 : 16;
+};
+
+#define VAX_DBL_BIAS   0x81
+#define IEEE_DBL_BIAS  0x3ff
+#define MASK(nbits)    ((1 << nbits) - 1)
+
+static struct dbl_limits {
+       struct  vax_double d;
+       struct  ieee_double ieee;
+} dbl_limits[2] = {
+       {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },   /* Max Vax */
+       { 0x0, 0x7ff, 0x0, 0x0 }},                      /* Max IEEE */
+       {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},               /* Min Vax */
+       { 0x0, 0x0, 0x0, 0x0 }}                         /* Min IEEE */
+};
+
+#endif /* vax */
+
+
+bool_t
+xdr_double(xdrs, dp)
+       register XDR *xdrs;
+       double *dp;
+{
+       register int32_t *lp;
+#if defined(vax)
+       struct  ieee_double id;
+       struct  vax_double vd;
+       register struct dbl_limits *lim;
+       int i;
+#endif
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+#if !defined(vax)
+               lp = (int32_t *)dp;
+#else
+               vd = *((struct vax_double *)dp);
+               for (i = 0, lim = dbl_limits;
+                       i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+                       i++, lim++) {
+                       if ((vd.mantissa4 == lim->d.mantissa4) &&
+                               (vd.mantissa3 == lim->d.mantissa3) &&
+                               (vd.mantissa2 == lim->d.mantissa2) &&
+                               (vd.mantissa1 == lim->d.mantissa1) &&
+                               (vd.exp == lim->d.exp)) {
+                               id = lim->ieee;
+                               goto shipit;
+                       }
+               }
+               id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
+               id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
+               id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
+                               (vd.mantissa3 << 13) |
+                               ((vd.mantissa4 >> 3) & MASK(13));
+       shipit:
+               id.sign = vd.sign;
+               lp = (int32_t *)&id;
+#endif
+               return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp));
+
+       case XDR_DECODE:
+#if !defined(vax)
+               lp = (int32_t *)dp;
+               return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp));
+#else
+               lp = (int32_t *)&id;
+               if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp))
+                       return (FALSE);
+               for (i = 0, lim = dbl_limits;
+                       i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+                       i++, lim++) {
+                       if ((id.mantissa2 == lim->ieee.mantissa2) &&
+                               (id.mantissa1 == lim->ieee.mantissa1) &&
+                               (id.exp == lim->ieee.exp)) {
+                               vd = lim->d;
+                               goto doneit;
+                       }
+               }
+               vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
+               vd.mantissa1 = (id.mantissa1 >> 13);
+               vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
+                               (id.mantissa2 >> 29);
+               vd.mantissa3 = (id.mantissa2 >> 13);
+               vd.mantissa4 = (id.mantissa2 << 3);
+       doneit:
+               vd.sign = id.sign;
+               *dp = *((double *)&vd);
+               return (TRUE);
+#endif
+
+       case XDR_FREE:
+               return (TRUE);
+       }
+       return (FALSE);
+}
diff --git a/TBBT/trace_play/rpc/xdr_mem.c b/TBBT/trace_play/rpc/xdr_mem.c
new file mode 100755 (executable)
index 0000000..6b7fe4d
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef lint
+static char sfs_xdr_mem_id[] = "@(#)xdr_mem.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_mem.c       2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/osdep.h"
+
+static bool_t  xdrmem_getlong(XDR *, int32_t *);
+static bool_t  xdrmem_putlong(XDR *, int32_t *);
+static bool_t  xdrmem_getbytes(XDR *, void *, uint_t);
+static bool_t  xdrmem_putbytes(XDR *, void *, uint_t);
+static uint_t  xdrmem_getpos(XDR *);
+static bool_t  xdrmem_setpos(XDR *, uint_t);
+static int32_t *xdrmem_inline(XDR *, uint_t);
+static void    xdrmem_destroy(XDR *);
+
+static struct  xdr_ops xdrmem_ops = {
+       xdrmem_getlong,
+       xdrmem_putlong,
+       xdrmem_getbytes,
+       xdrmem_putbytes,
+       xdrmem_getpos,
+       xdrmem_setpos,
+       xdrmem_inline,
+       xdrmem_destroy
+};
+
+/*
+ * The procedure xdrmem_create initializes a stream descriptor for a
+ * memory buffer.  
+ */
+void
+xdrmem_create(
+       XDR *xdrs,
+       void *addr,
+       uint_t size,
+       enum xdr_op op)
+{
+
+       xdrs->x_op = op;
+       xdrs->x_ops = &xdrmem_ops;
+       xdrs->x_private = xdrs->x_base = addr;
+       xdrs->x_handy = size;
+}
+
+/* ARGSUSED */
+static void
+xdrmem_destroy(XDR *xdrs)
+{
+}
+
+static bool_t
+xdrmem_getlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       if ((xdrs->x_handy -= sizeof(int32_t)) < 0)
+               return (FALSE);
+       *lp = (int32_t)ntohl((uint32_t)(*((int32_t *)(xdrs->x_private))));
+       xdrs->x_private += sizeof(int32_t);
+       return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       if ((xdrs->x_handy -= sizeof(int32_t)) < 0)
+               return (FALSE);
+       *(int32_t *)xdrs->x_private = (int32_t)htonl((uint32_t)(*lp));
+       xdrs->x_private += sizeof(int32_t);
+       return (TRUE);
+}
+
+static bool_t
+xdrmem_getbytes(
+       XDR *xdrs,
+       void *addr,
+       uint_t len)
+{
+
+       if ((xdrs->x_handy -= len) < 0)
+               return (FALSE);
+       memmove(addr, xdrs->x_private, len);
+       xdrs->x_private += len;
+       return (TRUE);
+}
+
+static bool_t
+xdrmem_putbytes(
+       XDR *xdrs,
+       void *addr,
+       uint_t len)
+{
+
+       if ((xdrs->x_handy -= len) < 0)
+               return (FALSE);
+       memmove(xdrs->x_private, addr, len);
+       xdrs->x_private += len;
+       return (TRUE);
+}
+
+static uint_t
+xdrmem_getpos(
+       XDR *xdrs)
+{
+
+       return ((uint_t)xdrs->x_private - (uint_t)xdrs->x_base);
+}
+
+static bool_t
+xdrmem_setpos(
+       XDR *xdrs,
+       uint_t pos)
+{
+       char * newaddr = xdrs->x_base + pos;
+       char * lastaddr = xdrs->x_private + xdrs->x_handy;
+
+       if ((int32_t)newaddr > (int32_t)lastaddr)
+               return (FALSE);
+       xdrs->x_private = newaddr;
+       xdrs->x_handy = (int)lastaddr - (int)newaddr;
+       return (TRUE);
+}
+
+static int32_t *
+xdrmem_inline(
+       XDR *xdrs,
+       uint_t len)
+{
+       int32_t *buf = 0;
+
+       if (xdrs->x_handy >= len) {
+               xdrs->x_handy -= len;
+               buf = (int32_t *) xdrs->x_private;
+               xdrs->x_private += len;
+       }
+       return (buf);
+}
diff --git a/TBBT/trace_play/rpc/xdr_rec.c b/TBBT/trace_play/rpc/xdr_rec.c
new file mode 100755 (executable)
index 0000000..0047c44
--- /dev/null
@@ -0,0 +1,608 @@
+#ifndef lint
+static char sfs_xdr_rec_id[] = "@(#)xdr_rec.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_rec.c       2.2 88/08/01 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
+ * layer above tcp (for rpc's use).
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These routines interface XDRSTREAMS to a tcp/ip connection.
+ * There is a record marking layer between the xdr stream
+ * and the tcp transport level.  A record is composed on one or more
+ * record fragments.  A record fragment is a thirty-two bit header followed
+ * by n bytes of data, where n is contained in the header.  The header
+ * is represented as a htonl(uint32_t).  Thegh order bit encodes
+ * whether or not the fragment is the last fragment of the record
+ * (1 => fragment is last, 0 => more fragments to follow. 
+ * The other 31 bits encode the byte length of the fragment.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/osdep.h"
+
+static bool_t  xdrrec_getlong(XDR *, int32_t *);
+static bool_t  xdrrec_putlong(XDR *, int32_t *);
+static bool_t  xdrrec_getbytes(XDR *, void *, uint_t);
+static bool_t  xdrrec_putbytes(XDR *, void *, uint_t);
+static uint_t  xdrrec_getpos(XDR *);
+static bool_t  xdrrec_setpos(XDR *, uint_t);
+static int32_t *xdrrec_inline(XDR *, uint_t);
+static void    xdrrec_destroy(XDR *);
+
+static struct  xdr_ops xdrrec_ops = {
+       xdrrec_getlong,
+       xdrrec_putlong,
+       xdrrec_getbytes,
+       xdrrec_putbytes,
+       xdrrec_getpos,
+       xdrrec_setpos,
+       xdrrec_inline,
+       xdrrec_destroy
+};
+
+/*
+ * A record is composed of one or more record fragments.
+ * A record fragment is a two-byte header followed by zero to
+ * 2**32-1 bytes.  The header is treated as a long unsigned and is
+ * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
+ * are a byte count of the fragment.  The highest order bit is a boolean:
+ * 1 => this fragment is the last fragment of the record,
+ * 0 => this fragment is followed by more fragment(s).
+ *
+ * The fragment/record machinery is not general;  it is constructed to
+ * meet the needs of xdr and rpc based on tcp.
+ */
+
+#define LAST_FRAG (0x80000000)
+
+typedef struct rec_strm {
+       void * tcp_handle;
+       void * the_buffer;
+       /*
+        * out-goung bits
+        */
+       int (*writeit)();
+       char *out_base;         /* output buffer (points to frag header) */
+       char *out_finger;       /* next output position */
+       char *out_boundry;      /* data cannot up to this address */
+       uint32_t *frag_header;  /* beginning of curren fragment */
+       bool_t frag_sent;       /* true if buffer sent in middle of record */
+       /*
+        * in-coming bits
+        */
+       int (*readit)();
+       uint32_t in_size;       /* fixed size of the input buffer */
+       char *in_base;
+       char *in_finger;        /* location of next byte to be had */
+       char *in_boundry;       /* can read up to this location */
+       int32_t fbtbc;          /* fragment bytes to be consumed */
+       bool_t last_frag;
+       uint_t sendsize;
+       uint_t recvsize;
+} RECSTREAM;
+
+
+static uint_t  fix_buf_size(uint_t);
+static bool_t  flush_out(RECSTREAM *, bool_t);
+static bool_t  set_input_fragment(RECSTREAM *);
+static bool_t  skip_input_bytes(RECSTREAM *, int32_t);
+static bool_t  get_input_bytes(RECSTREAM *, char *, int);
+
+/*
+ * Create an xdr handle for xdrrec
+ * xdrrec_create fills in xdrs.  Sendsize and recvsize are
+ * send and recv buffer sizes (0 => use default).
+ * tcp_handle is an opaque handle that is passed as the first parameter to
+ * the procedures readit and writeit.  Readit and writeit are read and
+ * write respectively.   They are like the system
+ * calls expect that they take an opaque handle rather than an fd.
+ */
+void
+xdrrec_create(
+       XDR *xdrs,
+       uint_t sendsize,
+       uint_t recvsize,
+       void * tcp_handle,
+       int (*readit)(),  /* like read, but pass it a tcp_handle, not sock */
+       int (*writeit)())  /* like write, but pass it a tcp_handle, not sock */
+{
+       RECSTREAM *rstrm =
+               (RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
+
+       if (rstrm == NULL) {
+               (void)fprintf(stderr, "xdrrec_create: out of memory\n");
+               /* 
+                *  This is bad.  Should rework xdrrec_create to 
+                *  return a handle, and in this case return NULL
+                */
+               return;
+       }
+       /*
+        * adjust sizes and allocate buffer quad byte aligned
+        */
+       rstrm->sendsize = sendsize = fix_buf_size(sendsize);
+       rstrm->recvsize = recvsize = fix_buf_size(recvsize);
+       rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
+       if (rstrm->the_buffer == NULL) {
+               (void)fprintf(stderr, "xdrrec_create: out of memory\n");
+               return;
+       }
+       for (rstrm->out_base = rstrm->the_buffer;
+               (uint_t)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
+               rstrm->out_base++);
+       rstrm->in_base = rstrm->out_base + sendsize;
+       /*
+        * now the rest ...
+        */
+       xdrs->x_ops = &xdrrec_ops;
+       xdrs->x_private = (void *)rstrm;
+       rstrm->tcp_handle = tcp_handle;
+       rstrm->readit = readit;
+       rstrm->writeit = writeit;
+       rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
+       rstrm->frag_header = (uint32_t *)rstrm->out_base;
+       rstrm->out_finger += sizeof(uint32_t);
+       rstrm->out_boundry += sendsize;
+       rstrm->frag_sent = FALSE;
+       rstrm->in_size = recvsize;
+       rstrm->in_boundry = rstrm->in_base;
+       rstrm->in_finger = (rstrm->in_boundry += recvsize);
+       rstrm->fbtbc = 0;
+       rstrm->last_frag = TRUE;
+}
+
+
+/*
+ * The reoutines defined below are the xdr ops which will go into the
+ * xdr handle filled in by xdrrec_create.
+ */
+
+static bool_t
+xdrrec_getlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+       int32_t *buflp = (int32_t *)(rstrm->in_finger);
+       int32_t mylong;
+
+       /* first try the inline, fast case */
+       if ((rstrm->fbtbc >= sizeof(int32_t)) &&
+               (((int)rstrm->in_boundry - (int)buflp) >= sizeof(int32_t))) {
+               *lp = (int32_t)ntohl((uint32_t)(*buflp));
+               rstrm->fbtbc -= sizeof(int32_t);
+               rstrm->in_finger += sizeof(int32_t);
+       } else {
+               if (! xdrrec_getbytes(xdrs, (void *)&mylong, sizeof(int32_t)))
+                       return (FALSE);
+               *lp = (int32_t)ntohl((uint32_t)mylong);
+       }
+       return (TRUE);
+}
+
+static bool_t
+xdrrec_putlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+       int32_t *dest_lp = ((int32_t *)(rstrm->out_finger));
+
+       if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
+               /*
+                * this case should almost never happen so the code is
+                * inefficient
+                */
+               rstrm->out_finger -= sizeof(int32_t);
+               rstrm->frag_sent = TRUE;
+               if (! flush_out(rstrm, FALSE))
+                       return (FALSE);
+               dest_lp = ((int32_t *)(rstrm->out_finger));
+               rstrm->out_finger += sizeof(int32_t);
+       }
+       *dest_lp = (int32_t)htonl((uint32_t)(*lp));
+       return (TRUE);
+}
+
+static bool_t  /* must manage buffers, fragments, and records */
+xdrrec_getbytes(
+       XDR *xdrs,
+       void *baddr,
+       uint_t len)
+{
+       char *addr = baddr;
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+       int current;
+
+       while (len > 0) {
+               current = rstrm->fbtbc;
+               if (current == 0) {
+                       if (rstrm->last_frag)
+                               return (FALSE);
+                       if (! set_input_fragment(rstrm))
+                               return (FALSE);
+                       continue;
+               }
+               current = (len < current) ? len : current;
+               if (! get_input_bytes(rstrm, addr, current))
+                       return (FALSE);
+               addr += current; 
+               rstrm->fbtbc -= current;
+               len -= current;
+       }
+       return (TRUE);
+}
+
+static bool_t
+xdrrec_putbytes(
+       XDR *xdrs,
+       void *baddr,
+       uint_t len)
+{
+       char *addr = baddr;
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+       int current;
+
+       while (len > 0) {
+               current = (uint_t)rstrm->out_boundry - (uint_t)rstrm->out_finger;
+               current = (len < current) ? len : current;
+               memmove(rstrm->out_finger, addr, current);
+               rstrm->out_finger += current;
+               addr += current;
+               len -= current;
+               if (rstrm->out_finger == rstrm->out_boundry) {
+                       rstrm->frag_sent = TRUE;
+                       if (! flush_out(rstrm, FALSE))
+                               return (FALSE);
+               }
+       }
+       return (TRUE);
+}
+
+static uint_t
+xdrrec_getpos(
+       XDR *xdrs)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+       int32_t pos;
+
+       pos = lseek((int)rstrm->tcp_handle, (int32_t) 0, 1);
+       if (pos != -1)
+               switch (xdrs->x_op) {
+
+               case XDR_ENCODE:
+                       pos += rstrm->out_finger - rstrm->out_base;
+                       break;
+
+               case XDR_DECODE:
+                       pos -= rstrm->in_boundry - rstrm->in_finger;
+                       break;
+
+               default:
+                       pos = (uint_t) -1;
+                       break;
+               }
+       return ((uint_t) pos);
+}
+
+static bool_t
+xdrrec_setpos(
+       XDR *xdrs,
+       uint_t pos)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+       uint_t currpos = xdrrec_getpos(xdrs);
+       int delta = currpos - pos;
+       char *newpos;
+
+       if ((int)currpos != -1)
+               switch (xdrs->x_op) {
+
+               case XDR_ENCODE:
+                       newpos = rstrm->out_finger - delta;
+                       if ((newpos > (char *)(rstrm->frag_header)) &&
+                               (newpos < rstrm->out_boundry)) {
+                               rstrm->out_finger = newpos;
+                               return (TRUE);
+                       }
+                       break;
+
+               case XDR_DECODE:
+                       newpos = rstrm->in_finger - delta;
+                       if ((delta < (int)(rstrm->fbtbc)) &&
+                               (newpos <= rstrm->in_boundry) &&
+                               (newpos >= rstrm->in_base)) {
+                               rstrm->in_finger = newpos;
+                               rstrm->fbtbc -= delta;
+                               return (TRUE);
+                       }
+                       break;
+               }
+       return (FALSE);
+}
+
+static int32_t *
+xdrrec_inline(
+       XDR *xdrs,
+       uint_t len)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+       int32_t * buf = NULL;
+
+       switch (xdrs->x_op) {
+
+       case XDR_ENCODE:
+               if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
+                       buf = (int32_t *) rstrm->out_finger;
+                       rstrm->out_finger += len;
+               }
+               break;
+
+       case XDR_DECODE:
+               if ((len <= rstrm->fbtbc) &&
+                       ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
+                       buf = (int32_t *) rstrm->in_finger;
+                       rstrm->fbtbc -= len;
+                       rstrm->in_finger += len;
+               }
+               break;
+       }
+       return (buf);
+}
+
+static void
+xdrrec_destroy(
+       XDR *xdrs)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+
+       mem_free(rstrm->the_buffer,
+               rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
+       mem_free((void *)rstrm, sizeof(RECSTREAM));
+}
+
+
+/*
+ * Exported routines to manage xdr records
+ */
+
+/*
+ * Before reading (deserializing from the stream, one should always call
+ * this procedure to guarantee proper record alignment.
+ */
+bool_t
+xdrrec_skiprecord(
+       XDR *xdrs)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+       while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+               if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+                       return (FALSE);
+               rstrm->fbtbc = 0;
+               if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+                       return (FALSE);
+       }
+       rstrm->last_frag = FALSE;
+       return (TRUE);
+}
+
+/*
+ * Look ahead fuction.
+ * Returns TRUE iff there is no more input in the buffer 
+ * after consuming the rest of the current record.
+ */
+bool_t
+xdrrec_eof(
+       XDR *xdrs)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+       while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+               if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+                       return (TRUE);
+               rstrm->fbtbc = 0;
+               if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+                       return (TRUE);
+       }
+       if (rstrm->in_finger == rstrm->in_boundry)
+               return (TRUE);
+       return (FALSE);
+}
+
+/*
+ * The client must tell the package when an end-of-record has occurred.
+ * The second paraemters tells whether the record should be flushed to the
+ * (output) tcp stream.  (This let's the package support batched or
+ * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
+ */
+bool_t
+xdrrec_endofrecord(
+       XDR *xdrs,
+       bool_t sendnow)
+{
+       RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+       uint32_t len;  /* fragment length */
+
+       if (sendnow || rstrm->frag_sent ||
+               ((uint32_t)rstrm->out_finger + sizeof(uint32_t) >=
+               (uint32_t)rstrm->out_boundry)) {
+               rstrm->frag_sent = FALSE;
+               return (flush_out(rstrm, TRUE));
+       }
+       len = (uint32_t)(rstrm->out_finger) - (uint32_t)(rstrm->frag_header) -
+          sizeof(uint32_t);
+       *(rstrm->frag_header) = htonl((uint32_t)len | (uint32_t)LAST_FRAG);
+       rstrm->frag_header = (uint32_t *)rstrm->out_finger;
+       rstrm->out_finger += sizeof(uint32_t);
+       return (TRUE);
+}
+
+
+/*
+ * Internal useful routines
+ */
+static bool_t
+flush_out(
+       RECSTREAM *rstrm,
+       bool_t eor)
+{
+       uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
+       uint32_t len = (uint32_t)(rstrm->out_finger) - 
+               (uint32_t)(rstrm->frag_header) - sizeof(uint32_t);
+
+       *(rstrm->frag_header) = htonl(len | eormask);
+       len = (uint32_t)(rstrm->out_finger) - (uint32_t)(rstrm->out_base);
+       if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
+               != (int)len)
+               return (FALSE);
+       rstrm->frag_header = (uint32_t *)rstrm->out_base;
+       rstrm->out_finger = (char *)rstrm->out_base + sizeof(uint32_t);
+       return (TRUE);
+}
+
+static bool_t  /* knows nothing about records!  Only about input buffers */
+fill_input_buf(
+       RECSTREAM *rstrm)
+{
+       char *where;
+       uint_t i;
+       int len;
+
+       where = rstrm->in_base;
+       i = (uint_t)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
+       where += i;
+       len = rstrm->in_size - i;
+       if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
+               return (FALSE);
+       rstrm->in_finger = where;
+       where += len;
+       rstrm->in_boundry = where;
+       return (TRUE);
+}
+
+static bool_t  /* knows nothing about records!  Only about input buffers */
+get_input_bytes(
+       RECSTREAM *rstrm,
+       char *addr,
+       int len)
+{
+       int current;
+
+       while (len > 0) {
+               current = (int)rstrm->in_boundry - (int)rstrm->in_finger;
+               if (current == 0) {
+                       if (! fill_input_buf(rstrm))
+                               return (FALSE);
+                       continue;
+               }
+               current = (len < current) ? len : current;
+               memmove(addr, rstrm->in_finger, current);
+               rstrm->in_finger += current;
+               addr += current;
+               len -= current;
+       }
+       return (TRUE);
+}
+
+static bool_t  /* next two bytes of the input stream are treated as a header */
+set_input_fragment(
+       RECSTREAM *rstrm)
+{
+       uint32_t header;
+
+       if (! get_input_bytes(rstrm, (void *)&header, sizeof(header)))
+               return (FALSE);
+       header = (int32_t)ntohl(header);
+       rstrm->last_frag = ((header & (uint32_t)LAST_FRAG) == 0) ? FALSE : TRUE;
+       rstrm->fbtbc = header & (~LAST_FRAG);
+       return (TRUE);
+}
+
+static bool_t  /* consumes input bytes; knows nothing about records! */
+skip_input_bytes(
+       RECSTREAM *rstrm,
+       int32_t cnt)
+{
+       int current;
+
+       while (cnt > 0) {
+               current = (int)rstrm->in_boundry - (int)rstrm->in_finger;
+               if (current == 0) {
+                       if (! fill_input_buf(rstrm))
+                               return (FALSE);
+                       continue;
+               }
+               current = (cnt < current) ? cnt : current;
+               rstrm->in_finger += current;
+               cnt -= current;
+       }
+       return (TRUE);
+}
+
+static uint_t
+fix_buf_size(
+       uint_t s)
+{
+
+       if (s < 100)
+               s = 4000;
+       return (RNDUP(s));
+}
diff --git a/TBBT/trace_play/rpc/xdr_reference.c b/TBBT/trace_play/rpc/xdr_reference.c
new file mode 100755 (executable)
index 0000000..56fc99c
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef lint
+static char sfs_xdr_reference_id[] = "@(#)xdr_reference.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
+#endif
+
+/*
+ * xdr_reference.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * "pointers".  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+
+#define LASTUNSIGNED   ((uint_t)0-1)
+
+/*
+ * XDR an indirect pointer
+ * xdr_reference is for recursively translating a structure that is
+ * referenced by a pointer inside the structure that is currently being
+ * translated.  pp references a pointer to storage. If *pp is null
+ * the  necessary storage is allocated.
+ * size is the sizeof the referneced structure.
+ * proc is the routine to handle the referenced structure.
+ */
+bool_t
+xdr_reference(
+       XDR *xdrs,
+       void **pp,              /* the pointer to work on */
+       uint_t size,            /* size of the object pointed to */
+       xdrproc_t proc)         /* xdr routine to handle the object */
+{
+       void *loc = *pp;
+       bool_t stat;
+
+       if (loc == NULL)
+               switch (xdrs->x_op) {
+               case XDR_FREE:
+                       return (TRUE);
+
+               case XDR_DECODE:
+                       *pp = loc = (void *) mem_alloc(size);
+                       if (loc == NULL) {
+                               (void) fprintf(stderr,
+                                   "xdr_reference: out of memory\n");
+                               return (FALSE);
+                       }
+                       memset(loc, '\0', (int)size);
+                       break;
+       }
+
+       stat = (*proc)(xdrs, loc, LASTUNSIGNED);
+
+       if (xdrs->x_op == XDR_FREE) {
+               mem_free(loc, size);
+               *pp = NULL;
+       }
+       return (stat);
+}
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ *  What's sent is actually a union:
+ *
+ *  union object_pointer switch (boolean b) {
+ *  case TRUE: object_data data;
+ *  case FALSE: void nothing;
+ *  }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(
+       XDR *xdrs,
+       void **objpp,
+       uint_t obj_size,
+       xdrproc_t xdr_obj)
+{
+
+       bool_t more_data;
+
+       more_data = (*objpp != NULL);
+       if (! xdr_bool(xdrs,&more_data)) {
+               return (FALSE);
+       }
+       if (! more_data) {
+               *objpp = NULL;
+               return (TRUE);
+       }
+       return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
diff --git a/TBBT/trace_play/rpc/xdr_stdio.c b/TBBT/trace_play/rpc/xdr_stdio.c
new file mode 100755 (executable)
index 0000000..8240089
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef lint
+static char sfs_xdr_stdio_id[] = "@(#)xdr_stdio.c     2.1     97/10/23";
+#endif
+/* @(#)xdr_stdio.c     2.1 88/07/29 4.0 RPCSRC */
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_stdio.c, XDR implementation on standard i/o file.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements a XDR on a stdio stream.
+ * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes
+ * from the stream.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "rpc/types.h"
+#include "rpc/xdr.h"
+#include "rpc/osdep.h" 
+
+static bool_t  xdrstdio_getlong(XDR *, int32_t *);
+static bool_t  xdrstdio_putlong(XDR *, int32_t *);
+static bool_t  xdrstdio_getbytes(XDR *, void *, uint_t);
+static bool_t  xdrstdio_putbytes(XDR *, void *, uint_t);
+static uint_t  xdrstdio_getpos(XDR *);
+static bool_t  xdrstdio_setpos(XDR *, uint_t);
+static int32_t *xdrstdio_inline(XDR *, uint_t);
+static void    xdrstdio_destroy(XDR *);
+
+/*
+ * Ops vector for stdio type XDR
+ */
+static struct xdr_ops  xdrstdio_ops = {
+       xdrstdio_getlong,       /* deseraialize a long int */
+       xdrstdio_putlong,       /* seraialize a long int */
+       xdrstdio_getbytes,      /* deserialize counted bytes */
+       xdrstdio_putbytes,      /* serialize counted bytes */
+       xdrstdio_getpos,        /* get offset in the stream */
+       xdrstdio_setpos,        /* set offset in the stream */
+       xdrstdio_inline,        /* prime stream for inline macros */
+       xdrstdio_destroy        /* destroy stream */
+};
+
+/*
+ * Initialize a stdio xdr stream.
+ * Sets the xdr stream handle xdrs for use on the stream file.
+ * Operation flag is set to op.
+ */
+void
+xdrstdio_create(
+       XDR *xdrs,
+       FILE *file,
+       enum xdr_op op)
+{
+
+       xdrs->x_op = op;
+       xdrs->x_ops = &xdrstdio_ops;
+       xdrs->x_private = (void *)file;
+       xdrs->x_handy = 0;
+       xdrs->x_base = 0;
+}
+
+/*
+ * Destroy a stdio xdr stream.
+ * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
+ */
+static void
+xdrstdio_destroy(
+       XDR *xdrs)
+{
+       (void)fflush((FILE *)xdrs->x_private);
+       /* xx should we close the file ?? */
+}
+
+static bool_t
+xdrstdio_getlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       if (fread((void *)lp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
+               return (FALSE);
+       *lp = ntohl(*lp);
+       return (TRUE);
+}
+
+static bool_t
+xdrstdio_putlong(
+       XDR *xdrs,
+       int32_t *lp)
+{
+
+       int32_t mycopy = htonl(*lp);
+       lp = &mycopy;
+
+       if (fwrite((void *)lp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
+               return (FALSE);
+       return (TRUE);
+}
+
+static bool_t
+xdrstdio_getbytes(
+       XDR *xdrs,
+       void * addr,
+       uint_t len)
+{
+
+       if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1))
+               return (FALSE);
+       return (TRUE);
+}
+
+static bool_t
+xdrstdio_putbytes(
+       XDR *xdrs,
+       void * addr,
+       uint_t len)
+{
+
+       if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1))
+               return (FALSE);
+       return (TRUE);
+}
+
+static uint_t
+xdrstdio_getpos(
+       XDR *xdrs)
+{
+
+       return ((uint_t) ftell((FILE *)xdrs->x_private));
+}
+
+static bool_t
+xdrstdio_setpos(
+       XDR *xdrs,
+       uint_t pos)
+{ 
+
+       return ((fseek((FILE *)xdrs->x_private, (int32_t)pos, 0) < 0) ?
+               FALSE : TRUE);
+}
+
+/* ARGSUSED */
+static int32_t *
+xdrstdio_inline(
+       XDR *xdrs,
+       uint_t len)
+{
+
+       /*
+        * Must do some work to implement this: must insure
+        * enough data in the underlying stdio buffer,
+        * that the buffer is aligned so that we can indirect through a
+        * int32_t *, and stuff this pointer in xdrs->x_buf.  Doing
+        * a fread or fwrite to a scratch buffer would defeat
+        * most of the gains to be had here and require storage
+        * management on this buffer, so we don't do this.
+        */
+       return (NULL);
+}
diff --git a/TBBT/trace_play/sem.c b/TBBT/trace_play/sem.c
new file mode 100644 (file)
index 0000000..3079f9b
--- /dev/null
@@ -0,0 +1,149 @@
+#include <sys/sem.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+extern int errno;
+
+#define SEMPERM 0777
+#define TRUE 1
+#define FALSE 0
+
+#define MAX_SEM 50
+struct {
+    int semid;
+    char name[256];
+} semname[MAX_SEM] =
+{
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+/*
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""},
+*/
+{0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}, {0, ""}
+} ;
+
+
+/* semaphore operations */
+
+int initsem(key_t key, int value)           /* create a semaphore */
+{
+  int status = 0;
+  int semid;
+
+  if ((semid = semget(key, 1, SEMPERM|IPC_CREAT|IPC_EXCL)) == -1) {
+       if (errno == EEXIST) {
+               printf("semget key %d already exist\n", key);
+           semid = semget(key, 1, 0);
+          }
+  } else {
+       status = semctl(semid, 0, SETVAL, value);
+       }
+
+  if (semid == -1 || status == -1) {
+          printf("%d:\n", getpid());
+       perror("initsem() failed");
+       return (-1);
+  } else
+       return semid;
+}
+
+//int getsem(key_t key, int setval)           /* create a semaphore */
+int getsem(key_t key)           /* create a semaphore */
+{
+  int status = 0;
+  int semid;
+
+  semid = semget(key, 1, 0);
+
+  if (semid == -1 || status == -1) {
+          printf("%d:\n", getpid());
+       perror("initsem() failed");
+       return (-1);
+  } else
+       return semid;
+}
+
+int waitsem(int semid)           /* wait on a semaphore */
+{
+  struct sembuf p_buf;
+#ifdef NO_SEM
+  return;
+#endif
+
+  p_buf.sem_num = 0;
+  p_buf.sem_op = -1;
+  p_buf.sem_flg = SEM_UNDO;
+
+  if (semop(semid, &p_buf, 1) == -1) {
+       printf("%d:", getpid());
+       perror("waitsem() failed");
+       exit(1);
+  } else
+       return (0);
+}
+
+int postsem(int semid)           /* post to a semaphore */
+{
+  struct sembuf v_buf;
+
+#ifdef NO_SEM
+  return;
+#endif
+
+
+  v_buf.sem_num = 0;
+  v_buf.sem_op = 1;
+  v_buf.sem_flg = SEM_UNDO;
+
+  if (semop(semid, &v_buf, 1) == -1) {
+       printf("%d:", getpid());
+       perror("postsem() failed");
+       exit(1);
+  } else
+       return (0);
+}
+
+void destsem(int semid)          /* destroy a semaphore */
+{
+  semctl(semid, 0, IPC_RMID, 0);
+}
+
+int dest_and_init_sem (key_t key, int value, char * name)
+{
+    int semid;
+    int i;
+    semid = getsem (key);
+    if (semid!=-1)
+        destsem (semid);
+    semid = initsem (key, value);
+    printf ("%s semid %d for key %d value %d \n", name, semid, key, value);
+                                                                                
+    if (semid == 0) {
+        printf ("semid == 0\n");
+        exit(0);
+    }
+                                                                                
+    for (i=0; i<MAX_SEM; i++) {
+        if (semname[i].semid == 0) {
+            semname[i].semid = semid;
+            strcpy(semname[i].name, name);
+            break;
+        }
+    }
+                                                                                
+    if (i==MAX_SEM) {
+        printf ("semname full\n");
+        exit (-1);
+    }
+                                                                                
+    return semid;
+}
+
+
diff --git a/TBBT/trace_play/sfs.1 b/TBBT/trace_play/sfs.1
new file mode 100755 (executable)
index 0000000..3c89a8a
--- /dev/null
@@ -0,0 +1,842 @@
+.\" @(#)sfs.1  2.1     97/10/23
+.\" See DESCR.SFS file for restrictions
+.\"
+.\" create man page by running 'tbl sfs.1 | nroff -man > sfs.cat'
+.\"
+.TH SFS 1 "5 October 1994"
+.SH NAME
+SFS \- Network File System server benchmark program
+.SH SYNOPSIS
+.B sfs
+[
+.B \-a access_pcnt
+] [
+.B \-A append_pcnt
+]
+.br
+[
+.B \-b blocksz_file
+] [
+.B \-B block_size
+] [
+.B \-d debug_level
+]
+.br
+[
+.B \-D dir_cnt
+] [
+.B \-f file_set_delta
+] [
+.B \-F file_cnt
+] [
+.B \-i
+] [
+.B \-l load
+]
+.br
+[
+.B \-m mix_file
+] [
+.B \-M prime_client_hostname
+]
+.br
+[
+.B \-N client_num
+] [
+.B \-p processes
+] [
+.B \-P
+] [
+.B \-Q
+]
+.br
+[
+.B \-R biod_reads
+] [
+[
+.B \-S symlink_cnt
+] [
+.B \-t time
+] [
+.B \-T
+]
+.br
+[
+.B \-V
+] [
+.B \-W biod_writes
+] [
+.B \-w warmup_time
+] [
+.B \-z
+]
+.br
+[
+.B server:/directory ...
+]
+.LP
+.B sfs3
+[
+.B \-a access_pcnt
+] [
+.B \-A append_pcnt
+]
+.br
+[
+.B \-b blocksz_file
+] [
+.B \-B block_size
+] [
+.B \-d debug_level
+]
+.br
+[
+.B \-D dir_cnt
+] [
+.B \-f file_set_delta
+] [
+.B \-F file_cnt
+] [
+.B \-i
+] [
+.B \-l load
+]
+.br
+[
+.B \-m mix_file
+] [
+.B \-M prime_client_hostname
+]
+.br
+[
+.B \-N client_num
+] [
+.B \-p processes
+] [
+.B \-P
+] [
+.B \-Q
+]
+.br
+[
+.B \-R biod_reads
+] [
+[
+.B \-S symlink_cnt
+] [
+.B \-t time
+] [
+.B \-T
+]
+.br
+[
+.B \-V
+] [
+.B \-W biod_writes
+] [
+.B \-w warmup_time
+] [
+.B \-z
+]
+.br
+[
+.B server:/directory ...
+]
+.SH DESCRIPTION
+Normally,
+.B SFS
+is executed via the
+.B sfs_mgr
+script which controls
+.B SFS
+execution on one or more
+.SM NFS
+client systems using a single user interface.
+.P
+.B SFS
+is a Network File System server benchmark.
+It runs on one or more 
+.SM NFS
+client machines to generate an artificial load
+consisting of a particular mix of
+.SM NFS
+operations on a particular set of files
+residing on the server being tested.
+The benchmark reports the average response time of the
+.SM NFS
+requests in milliseconds for the requested target load.
+The response time is the dependent variable.
+Load can be generated for a specific amount of time,
+or for a specific number of
+.SM NFS
+calls.
+.P
+.B SFS
+can also be used to characterize server performance.
+Nearly all of the major factors that influence NFS performance
+can be controlled using
+.B SFS
+command line arguments. Normally however, only the
+.B \-l load
+option used.
+Other commonly used options include the
+.B \-t time
+,
+.B \-p processes
+,
+.B \-m mix_file
+options.
+The remaining options are used to adjust specific parameters that affect
+.SM NFS
+performance.
+If these options are used, the results produced will be non\-standard,
+and thus, will not be comparable to tests run with other option settings.
+.P
+Normally,
+.B SFS
+is used as a benchmark program to measure the
+.SM NFS
+performance
+of a particular server machine at different load levels.
+In this case,
+the preferred measurement is to make a series of benchmark runs, 
+varying the load factor for each run
+in order to produce a performance/load curve.
+Each point in the curve
+represents the server's response time at a specific load.
+.P
+.B SFS
+generates and transmits
+.SM NFS
+packets over the network to the server directly from the benchmark program,
+without using the client's local NFS service.
+This reduces the effect of the client NFS implementation on results,
+and makes comparison of different servers more client-independent.
+However, not all client implementation effects have been eliminated.
+Since the benchmark does by-pass much of the client NFS implementation
+(including operating system level data caching and write behind),
+.B SFS
+can only be used to measure server performance.
+.P
+Although
+.B SFS
+can be run between a single client and single server pair of machines,
+a more accurate measure of server performance is obtained
+by executing the benchmark on a number of clients simultaneously.
+Not only does this present a more realistic model of
+.SM NFS
+usage, but also improves the chances that maximum performance
+is limited by a lack of resources on the server machine,
+rather than on a single client machine.
+.P
+In order to facilitate running
+.B SFS
+on a number of clients simultaneously,
+an accompanying program called
+.B sfs_mgr
+provides a mechanism to run and synchronize the execution of multiple
+instances of
+.B SFS
+spread across multiple clients and multiple networks
+all generating load to the same
+.SM NFS
+server.
+In general,
+.B sfs_mgr
+should be used to run both single- and multiple-client tests.
+.P
+.B SFS
+employs a number of sub\-processes, each with its own test directory named
+.B ./testdir<n>
+(where <n> is a number from 0 to
+.B processes
+\- 1.)
+A standard set of files is created in the test directory.
+.P
+If multiple
+.B directories
+are specified on the command line, the
+.B SFS
+processes will be evenly distributed among the directories.
+This will produce a balanced load across each of the directories.
+.P
+The mix of
+.SM NFS
+operations generated can be set from a user defined mix file.
+The format of the file consists of a simple format, the first
+line contains the string "SFS MIXFILE VERSION 2" followed by
+each line containing the operation name and the percentage (eg.
+"write 12"). The total percentages must equal 100.
+Operations with not specified will never be called by
+.B SFS.
+.SH SFS OPTIONS
+.TP
+.B \-a access_pcnt
+The percentage of I/O files to access.
+The access percent can be set from 0 to 100 percent.
+The default is 10% access.
+.TP
+.B \-A append_pcnt
+The percentage of write operations that append data to files
+rather than overwriting existing data.
+The append percent can be set from 0 to 100 percent.
+The default is 70% append.
+.TP
+.B \-b blocksz_file
+The name of a file containing a block transfer size distribution specification.
+The format of the file and the default values are discussed below
+under "Block Size Distribution".
+.TP
+.B \-B block_size
+The maximum number of Kilo-bytes (KB) contained in any one data transfer block.
+The valid range of values is from 1 to 8 KB.
+The default maximum is 8 KB per transfer.
+.TP
+.B \-d debug_level
+The debugging level, with higher values producing more debugging output.
+When the benchmark is executed with debugging enabled,
+the results are invalid.
+The debug level must be greater than zero.
+.TP
+.B \-D dir_cnt
+The number of files in each directory, the number of directories varies with
+load load.
+The default is 30 files per directory.
+.TP
+.B \-f file_set_delta
+The percentage change in file set size.
+The change percent can be set from 0 to 100 percent.
+The default is 10% append.
+.TP
+.B \-F file_cnt
+The number of files to be used for read and write operations.
+The file count must be greater than 0.
+The default is 100 files.
+.TP
+.B \-i
+Run the test in interactive mode,
+pausing for user input before starting the test.
+The default setting is to run the test automatically.
+.TP
+.B \-l load
+The number of NFS calls per second to generate from each client machine.
+The load must be greater than the number of processes
+(see the "\-p processes" option).
+The default is to generate 60 calls/sec on each/client.
+.TP
+.B \-m mix_file
+The name of a file containing the operation mix specification.
+The format of the file and the default values are discussed below
+under "Operation Mix".
+.TP
+.B \-p processes
+The number of processes used to generate load on each client machine.
+The number of processes must be greater than 0.
+The default is 4 processes per client.
+.TP
+.B \-P
+Populate the test directories and then exit; don't run the test.
+This option can be used to examine the file set that the benchmark creates.
+The default is to populate the test directories and then
+execute the test automatically.
+.TP
+.B \-Q
+Run NFS over TCP.
+The default is UDP.
+.TP
+.B \-R biod_reads
+The maximum number of asynchronus reads issued to simulate biod behavior.
+The default is 2.
+.TP
+.B \-S symlink_cnt
+The number of symbolic links to be used for symlink operations.
+The symbolic link count must be greater than 0.
+The default is 20 symlinks.
+.TP
+.B \-t time
+The number of seconds to run the benchmark.
+The number of seconds must be greater than 0.
+The default is 300 seconds.
+(Run times less than 300 seconds may produce invalid results.)
+.TP
+.B \-T op_num
+Test a particular
+.SM NFS
+operation by executing it once.
+The valid range of operations is from 1 to 23.
+These values correspond to the procedure number
+for each operation type as defined in the
+.SM NFS
+protocol specification.
+The default is to run the benchmark, with no preliminary operation testing.
+.TP
+.B \-V
+Validate the correctness of the server's
+.SM NFS
+implementation.
+The option verifies the correctness of
+.SM NFS
+operations and data copies.
+The verification takes place immediately before executing the test,
+and does not affect the results reported by the test. 
+The default is not to verify server
+.SM NFS
+operation before beginning the test.
+.TP
+.B \-z
+Generate raw data dump of the individual data points
+for the test run.
+.TP
+.B \-w warmup
+The number of seconds to generate load before starting the timed test run.
+The goal is to reach a steady state and eliminate any variable startup costs,
+before beginning the test.
+The warm up time must be greater than or equal to 0 seconds.
+The default is a 60 second warmup period.
+.TP
+.B \-W biod_writes
+The maximum number of asynchronus writes issued to simulate biod behavior.
+The default is 2.
+.SH MULTI-CLIENT OPTIONS
+.B SFS
+also recognizes options that are only used when executing a multi-client test.
+These options are generated by
+.B sfs_mgr
+and should not be specified by an end-user.
+.TP
+.B \-M prime_client_hostname
+The hostname of the client machine where a multi-client test
+is being controlled from.
+This machine is designated as the "prime client".
+The prime client machine may also be executing the
+.B SFS
+load-generating code. There is no default value.
+.TP
+.B \-N client_num
+The client machine's unique identifier within a multi-client test,
+assigned by the
+.B sfs_mgr
+script.
+There is no default value.
+.\".TP
+.\".B \-R random_number_seed
+.\"The value used by the client to index into a table of random number seeds.
+.\"There is no default value.
+.SH OPERATION MIX
+The
+.B SFS
+default mix of operations for version 2 is:
+.sp
+.TS
+center;
+l l l l l l
+n n n n n n
+l l l l l l
+n n n n n n
+l l l l l l
+n n n n n n.
+null   getattr setattr root    lookup  readlink
+0%     26%     1%      0%      36%     7%
+read   wrcache write   create  remove  rename
+14%    7%      1%      1%      0%      0%
+link   symlink mkdir   rmdir   readdir fsstat
+0%     0%      0%      0%      6%      1%
+.TE
+.LP
+The
+.B SFS
+default mix of operations for version 3 is:
+.sp
+.TS
+center;
+l l l l l l
+n n n n n n
+l l l l l l
+n n n n n n
+l l l l l l
+n n n n n n
+l l l l l l
+n n n n n n.
+null   getattr setattr lookup  access  readlink
+0%     11%     1%      27%     7%      7%
+read   write   create  mkdir   symlink mknod
+18%    9%      1%      0%      0%      0%
+remove rmdir   rename  link    readdir readdirplus
+1%     0%      0%      0%      2%      9%
+fsstat fsinfo  pathconf        commit
+1%     0%      0%      5%
+.TE
+.P
+The format of the file consists of a simple format, the first
+line contains the string "SFS MIXFILE VERSION 2" followed by
+each line containing the operation name and the percentage (eg.
+"write 12"). The total percentages must equal 100.
+.SH FILE SET
+The default basic file set used by
+.B SFS
+consists of regular files varying in size from 1KB to 1MB used for read and
+write operations,
+and 20 symbolic links used for symbolic link operations.
+In addition to these, a small number of regular files are created
+and used for non-I/O operations (eg, getattr),
+and a small number of regular, directory, and symlink files may
+be added to this total due to creation operations (eg, mkdir).
+.P
+While these values can be controlled with command line options,
+some file set configurations may produce invalid results.
+If there are not enough files of a particular type,
+the specified mix of operations will not be achieved.
+Too many files of a particular type may produce
+thrashing effects on the server.
+.SH BLOCK SIZE DISTRIBUTION
+The block transfer size distribution is specified by a table of values.
+The first column gives the percent of operations that will be included in a
+any particular specific block transfer.
+The second column gives the number of blocks units that will be transferred.
+Normally the block unit size is 8KB.
+The third column is a boolean specifying
+whether a trailing fragment block should be transferred.
+The fragment size for each transfer is a random multiple of 1 KB,
+up to the block size - 1 KB.
+Two tables are used, one for read operation and one for write operations.
+The following tables give the default distributions
+for the read and write operations.
+.sp
+.TS
+center;
+c s s s
+c s s s
+r r r r
+r r r r
+c s s s
+n n n r.
+Read  - Default Block Transfer Size Distribution Table
+                       resulting transfer
+percent        block count     fragment        (8KB block size)
+0      0       0        0%    0 -   7 KB
+85     1       0       85%    8 -  15 KB
+8      2       1        8%   16 -  23 KB
+4      4       1        4%   32 -  39 KB
+2      8       1        2%   64 -  71 KB
+1      16      1        1%  128 - 135 KB
+.TE
+.sp 2
+.TS
+center;
+c s s s
+c s s s
+r r r r
+r r r r
+c s s s
+n n n r.
+Write  - Default Block Transfer Size Distribution Table
+                       resulting transfer
+percent        block count     fragment        (8KB block size)
+49     0       1       49%    0 -   7 KB
+36     1       1       36%    8 -  15 KB
+8      2       1        8%   16 -  23 KB
+4      4       1        4%   32 -  39 KB
+2      8       1        2%   64 -  71 KB
+1      16      1        1%  128 - 135 KB
+.TE
+.P
+A different distribution can be substituted by using the '-b' option.
+The format for the block size distribution file consists of the first
+three columns given above: percent, block count, and fragment.  Read
+and write distribution tables are identified by the keywords "Read" and
+"Write".  An example input file, using the default values, is given below:
+.sp
+.TS
+l s s
+n n n.
+Read
+0      0       0
+85     1       0
+8      2       1
+4      4       1
+2      8       1
+1      16      1
+.TE
+.TS
+l s s
+n n n.
+Write
+49     0       1
+36     1       1
+8      2       1
+4      4       1
+2      8       1
+1      16      1
+.TE
+.P
+A second aspect of the benchmark controlled
+by the block transfer size distribution table is the network data packet size.
+The distribution tables define the relative proportion
+of full block packets to fragment packets.
+For instance, the default tables have been constructed
+to produce a specific distribution of ethernet packet sizes
+for i/o operations by controlling the amount of data in each packet.
+The write packets produced consist of 50% 8-KB packets, and 50% 1-7 KB packets.
+The read packets consist of 90% 8-KB packets, and 10% 1-7 KB packets.
+These figures are determined by multiplying the percentage
+of type of transfer times the number of blocks and fragments generated,
+and adding the totals.
+These computations are performed below
+for the default block size distribution tables:
+.sp
+.TS
+c c c c c
+c c c c c
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+r r r l l
+r r r n n
+r r r l l.
+Read                   total   total
+percent        blocks  fragments       blocks  fragments
+0      0       0       0       0
+85     1       0       85      0
+8      2       1       16      8
+4      4       1       16      4
+2      8       1       16      2
+1      16      1       16      1
+                       ----    -----
+                       149     15
+                        90%      10%
+.TE
+.sp 3
+.TS
+r r r r r
+r r r r r
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+n n n n n
+r r r l l
+r r r n n
+r r r l l.
+Write                  total   total
+percent        blocks  fragments       blocks  fragments
+49     0       1       0       49
+36     1       1       36      36
+8      2       1       16      8
+4      4       1       16      4
+2      8       1       16      2
+1      16      1       16      1
+                       ----    ------
+                       100     100
+                        50%       50%
+.TE
+.SH USING SFS
+As with all benchmarks,
+.B SFS
+can only provide numbers that are useful
+if the test runs are set up carefully.
+Since it measures server performance,
+the client (or clients) should not limit throughput.
+The goal is to determine how well the server performs.
+Most tests involving a single client will be limited by the client's
+ability to generate load, not by the server's ability to handle more load.
+Whether this is the case can be determined by running the benchmark
+at successively greater load levels and finding the "knee of the curve"
+at which load level the response time begins to increase rapidly.
+Having found the knee of the curve, measurements of CPU utilization,
+disk i/o rates, and network utilization levels should be made in order
+to determine whether the performance bottleneck is due to the client
+or server.
+.P
+For the results reported by
+.B SFS
+to be meaningful, the tests should be run on an isolated network,
+and both the client and server should be as quiescent as possible during tests.
+.P
+High error rates on either the client or server
+can also cause delays due to retransmissions
+of lost or damaged packets.
+.B netstat(8)
+can be used to measure the network error
+and collision rates on the client and server.
+Also
+.B SFS
+reports the number of timed-out
+.SM RPC
+calls that occur during the test as bad calls.
+If the number of bad calls is too great,
+or the specified mix of operations is not achieved,
+.B SFS
+reports that the test run is "Invalid".
+In this case, the reported results should be examined 
+to determine the cause of the errors.
+.P
+To best simulate the effects of
+.SM NFS
+clients on the server, the test
+directories should be set up so that they are on at least two
+disk partitions exported by the server.
+.SM NFS
+operations tend to randomize disk access,
+so putting all of the
+.B SFS
+test directories on a single partition will not show realistic results.
+.P
+On all tests it is a good idea to run the tests repeatedly and compare results.
+If the difference between runs is large,
+the run time of the test should be increased
+until the variance in milliseconds per call is acceptably small.
+If increasing the length of time does not help,
+there may be something wrong with the experimental setup.
+.P
+The numbers generated by
+.B SFS
+are only useful for comparison if the test setup on the client machine
+is the same across different server configurations. 
+Changing the
+.B processes
+or
+.B mix
+parameters will produce numbers that can not be meaningfully compared.
+Changing the number of generator processes may affect the measured response
+time due to context switching or other delays on the client machine,
+while changing the mix of
+.SM NFS
+operations will change the whole nature of the experiment.
+Other changes to the client configuration may also effect the comparability
+of results.
+.P
+To do a comparison of different server configurations, first set up the
+client test directory and do
+.B SFS
+runs at different loads to be sure that the variability is
+reasonably low. Second, run
+.B SFS
+at different loads of interest and
+save the results. Third, change the server configuration (for example,
+add more memory, replace a disk controller, etc.). Finally, run the same
+.B SFS
+loads again and compare the results.
+.SH SEE ALSO
+.P
+The benchmark 
+.B README  
+file contains many pointers to other
+files which provide information concerning SFS.
+.SH ERROR MESSAGES
+.TP 10
+.B "illegal load value"
+The
+.B load
+argument following the
+.B \-l
+flag on the command line is not a positive number.
+.TP
+.B "illegal procs value"
+The
+.B processes
+argument following the
+.B \-p
+flag on the command line is not a positive number.
+.TP
+.B "illegal time value"
+The
+.B time
+argument following the
+.B \-t
+flag on the command line is not a positive number.
+.TP
+.B "bad mix file"
+The
+.B mix
+file argument following the
+.B \-m
+flag on the command line could not be accessed.
+.TP
+.B "can't fork"
+The parent couldn't fork the child processes. This usually results from
+lack of resources, such as memory or swap space.
+.TP
+.PD 0
+.B "can't open log file"
+.TP
+.B "can't stat log"
+.TP
+.B "can't truncate log"
+.TP
+.B "can't write sync file"
+.TP
+.B "can't write log"
+.TP
+.B "can't read log"
+.PD
+A problem occurred during the creation, truncation, reading or writing of the
+synchronization log file. The parent process creates the
+log file in /tmp and uses it to synchronize and communicate with its children.
+.TP
+.PD 0
+.B "can't open test directory"
+.TP
+.B "can't create test directory"
+.TP
+.B "can't cd to test directory"
+.TP
+.B "wrong permissions on test dir"
+.TP
+.B "can't stat testfile"
+.TP
+.B "wrong permissions on testfile"
+.TP
+.B "can't create rename file"
+.TP
+.B "can't create subdir"
+.PD
+A child process had problems creating or checking the contents of its
+test directory. This is usually due to a permission problem (for example
+the test directory was created by a different user) or a full file system.
+.TP
+.PD 0
+.B "op failed: "
+One of the internal pseudo\-NFS operations failed. The name of the operation,
+e.g. read, write, lookup, will be printed along with an indication of the
+nature of the failure.
+.TP
+.B "select failed"
+The select system call returned an unexpected error.
+.SH BUGS
+.P
+.B SFS
+can not be run on non\-NFS file systems.
+.P
+.P
+Shell scripts that execute
+.B SFS
+must catch and ignore SIGUSR1, SIGUSR2, and SIGALRM, (see signal(3)).
+These signals are used to synchronize the test processes.
+If one of these signals is not caught,
+the shell that is running the script will be killed.
+.SH FILES
+.PD 0
+.TP
+.B ./testdir*
+per process test directory
+.TP
+.B /tmp/sfs_log%d
+child process synchronization file
+.TP
+.B /tmp/sfs_CL%d
+client log file
+.TP
+.B /tmp/sfs_PC_sync
+prime client log file
+.TP
+.B /tmp/sfs_res
+prime results log file
+.PD
diff --git a/TBBT/trace_play/sfs3.full_speed b/TBBT/trace_play/sfs3.full_speed
new file mode 100755 (executable)
index 0000000..5237e99
Binary files /dev/null and b/TBBT/trace_play/sfs3.full_speed differ
diff --git a/TBBT/trace_play/sfs_2_ops.c b/TBBT/trace_play/sfs_2_ops.c
new file mode 100644 (file)
index 0000000..f50f353
--- /dev/null
@@ -0,0 +1,2131 @@
+#ifndef lint
+static char sfs_c_opsSid[] = "@(#)sfs_2_ops.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_ops.c ---------------------
+ *
+ *      RPC routines to implement the NFS protocol.
+ *
+ *.Local Routines
+ *     int op_null(void)
+ *     int op_getattr(void)
+ *     int op_setattr(int)
+ *     int op_nosys(void)
+ *     int op_lookup(void)
+ *     int op_readlink(void)
+ *     int op_read(int)
+ *     int op_write(int, int, int)
+ *     int op_create(void)
+ *     int op_remove(void)
+ *     int op_rename(void)
+ *     int op_link(void)
+ *     int op_symlink(void)
+ *     int op_mkdir(void)
+ *     int op_rmdir(void)
+ *     int op_readdir(void)
+ *     int op_fsstat(void)
+ *
+ *.Revision_History
+ *     20-Apr-92       Wittle          Fix i/o offsets randomization.
+ *     05-Jan-92       Pawlowski       Added hooks in for raw data dump.
+ *      04-Dec-91      Keith           Define string.h for SYSV/SVR4.
+ *     28-Nov-91       Teelucksingh    ANSI C
+ *     01-Aug-91       Santa Wiryaman  fix declaration of sfs_srandom()
+ *                                     and sfs_random()
+ *     25-Jun-91       Santa Wiryaman  op_rmdir bug fix: when reply==NFS_OK
+ *                                     Cur_file_ptr->state = Nonexistent
+ *     17-May-90       Richard Bean    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+/*
+ * --------------------  Local NFS ops function --------------------
+ */
+static int op_null(void);
+static int op_getattr(void);
+static int op_setattr(int);
+static int op_lookup(void);
+static int op_readlink(void);
+static int op_read(int);
+static int op_write(int, int, int);
+static int op_create(void);
+static int op_remove(void);
+static int op_rename(void);
+static int op_link(void);
+static int op_symlink(void);
+static int op_mkdir(void);
+static int op_rmdir(void);
+static int op_readdir(void);
+static int op_fsstat(void);
+static int op_nosys(void);
+static char *nfs2_strerror(int);
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+static sfs_op_type nfsv2_Ops[] = {
+
+/* name      mix   function        op    call  no  req  req  req  results */
+/*           pcnt                 class  targ call pcnt cnt  targ         */
+
+ { "null",        0, op_null,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    26, op_getattr,   Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, op_setattr,   Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     36, op_lookup,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, op_readlink,  Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       14, op_read,      Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       7, op_write,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, op_create,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, op_remove,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, op_rename,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, op_link,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, op_symlink,   Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, op_mkdir,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, op_rmdir,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     6, op_readdir,   Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, op_fsstat,           Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",     0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",     0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",     0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",      0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",   0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 0, op_nosys,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, 0,            Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+
+sfs_op_type *Ops;
+
+/*
+ * --------------------  RPC routines for NFS protocol --------------------
+ */
+
+void
+init_ops(void)
+{ 
+    Ops = nfsv2_Ops;
+    nfs_version = NFS_VERSION;
+} 
+
+/*
+ * The routines below attempt to do over-the-wire operations.
+ * Each op tries to cause one or more of a particular
+ * NFS operation to go over the wire.  OPs return the success
+ * of their NFS call(s).  Each OP records how many calls it
+ * actually made in global data.
+ *
+ * An array of file information is kept for files existing in
+ * the test directory.  File handles, attributes, names, etc
+ * are stored in this array.
+ *
+ */
+
+static int
+op_nosys(void)
+{
+    /*
+     * This is a generic catcher for operations that either don't
+     * exist or were never implemented.  We will be
+     * kind and simply mark it as a bad call.
+     */
+    Ops[TOTAL].results.bad_calls++;
+    return(0);
+
+} /* op_nosys */
+
+
+static int
+op_null(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[NULLCALL];
+    ret = 0;
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_NULL,
+                       xdr_void, (char *)0,
+                       xdr_void, (char *)0,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                   "%s: null_op call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_null */
+
+
+static int
+op_getattr(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    fhandle_t          fh;             /* fh to do op on */
+    attrstat           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[GETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_GETATTR,
+                       xdr_getattr, (char *) &fh,
+                       xdr_getattr, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: getattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                   "%s: getattr call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_getattr */
+
+
+/*
+ * perform an RPC setattr operation.  If 'truncate_size' is non-negative,
+ * truncate the file to that size.
+ */
+static int
+op_setattr(
+    int                truncate_size)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    sattrargs          args;
+    attrstat           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[SETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    args.attributes.mode = 0666;
+    args.attributes.uid = (unsigned int) -1;
+    args.attributes.gid = (unsigned int) -1;
+    args.attributes.size = (unsigned int) -1;
+    args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+    args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+
+    /* handle file truncations */
+    if (truncate_size >= 0) {
+       if (truncate_size > Cur_file_ptr->attributes2.size)
+           args.attributes.size = (unsigned int) 0;
+       else
+           args.attributes.size = (unsigned int) Cur_file_ptr->attributes2.size
+                                  - truncate_size;
+    }
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_SETATTR,
+                       xdr_setattr, (char *) &args,
+                       xdr_setattr, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: setattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                   "%s: setattr call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_setattr */
+
+
+static int
+op_lookup(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    diropargs          args;
+    diropres           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[LOOKUP];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.name = Cur_filename;
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_LOOKUP,
+                       xdr_lookup, (char *) &args,
+                       xdr_lookup, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file,
+                       NFS_FHSIZE);
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+            /* We do lookup Nonexistent and this is not an error */
+            if (reply.status != NFSERR_NOENT ||
+                        Cur_file_ptr->state != Nonexistent) {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                       "%s: lookup call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+               }
+            }
+
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: lookup call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_lookup */
+
+
+static int
+op_readlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    fhandle_t          fh;                     /* fh to do op on */
+    readlinkres                reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];
+    int                        len;                    /* length of symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[READLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    /*
+     * Note: this fh may be bogus because SYMLINK does
+     * not return a fh ... only a status.  So unless we have
+     * done a LOOKUP on this guy, the fh will probably be bad.
+     * If it is bad it shows up as a symlink error in the results.
+     */
+    (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+
+    /* Have lower layers fill in the data directly. */
+    reply.readlinkres_u.data = sym_data;
+    len = 0;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_READLINK,
+                       xdr_readlink, (char *) &fh,
+                       xdr_readlink, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           if (DEBUG_CHILD_RPC) {
+               len = reply.readlinkres_u.len;
+               sym_data[len] = '\0';
+               (void) fprintf(stderr, "%s: READLINK on %s returned %s\n",
+                                   sfs_Myname, Cur_filename, sym_data);
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                   "%s: readlink call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readlink */
+
+
+/*
+ * perform an RPC read operation of length 'xfer_size'
+ */
+static int
+op_read(
+    int                        xfer_size)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int                                cur_cnt;
+    int                                max_cnt;        /* packet ctrs */
+    char                       buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
+    readargs                   args;
+    readres                    reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                size;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[READ];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+
+    /*
+     * Don't allow a read of less than one block size
+     */
+    if (xfer_size < Bytes_per_block)
+       xfer_size = Bytes_per_block;
+
+    /*
+     * randomly choose an offset that is a multiple of the block size
+     * and constrained by making the transfer fit within the file
+     */
+    if (Cur_file_ptr->attributes2.size > xfer_size) {
+       args.offset = Bytes_per_block * (sfs_random() %
+                       (((Cur_file_ptr->attributes2.size - xfer_size)
+                       / Bytes_per_block) + 1));
+    } else
+       args.offset = 0;
+
+    /* first read the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block -1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       args.count = size;
+       args.totalcount = size;         /* unused */
+
+       /* Have lower layers fill in the data directly.  */
+       reply.readres_u.reply.data.data_val = buf;
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "read: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC_READ,
+                               xdr_read, (char *) &args,
+                               xdr_read, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = (rpc_stat == RPC_SUCCESS && reply.status == NFS_OK)
+                           ? reply.readres_u.reply.data.data_len : 0;
+           Dump_offset = args.offset;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS_OK) {
+                   Cur_file_ptr->state = Exists;
+                   Cur_file_ptr->attributes2 =
+                                       reply.readres_u.reply.attributes;
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   size = reply.readres_u.reply.data.data_len;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: READ %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+                   args.offset += size;
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: read call NFS error %s on file %d\n",
+                               sfs_Myname, nfs2_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                           "%s: read call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for reading max_cnt packets */
+    } /* for buffers and fragments */
+    return(ret);
+
+} /* op_read */
+
+
+char *
+init_write_buffer(
+    void)
+{
+    uint32_t *bp;
+    static uint32_t write_buf[DEFAULT_MAX_BUFSIZE / sizeof(uint32_t)];
+    uint32_t *be  = write_buf + (sizeof(write_buf) /
+                                               sizeof(uint32_t));
+
+    if (write_buf[0] != (uint32_t)0xdeadbeef) {
+        for (bp = write_buf; bp < be; bp++)
+            *bp = (uint32_t)0xdeadbeef;
+    }
+    return (char *)write_buf;
+}
+
+/*
+ * Perform and RPC write operation of length 'xfer_size'.  If 'append_flag'
+ * is true, then write the data to the end of the file.
+ */
+/* ARGSUSED2 */
+static int
+op_write(
+    int                        xfer_size,
+    int                        append_flag,
+    int                        stable)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    static char                        *buf = NULL;    /* the data buffer */
+    int                                size;           /* size of data write */
+    int                                cur_cnt;        /* controls # NFS calls */
+    int                                max_cnt;
+    writeargs                  args;
+    attrstat                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    /*
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+    op_ptr = &Ops[WRITE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+    args.beginoffset = 0;      /* unused */
+
+    if (append_flag == 1) {
+       args.offset = Cur_file_ptr->attributes2.size;
+    } else {
+       /*
+        * randomly choose an offset that is a multiple of the block size
+        * and constrained by making the transfer fit within the file
+        */
+       if (Cur_file_ptr->attributes2.size > xfer_size) {
+           args.offset = Bytes_per_block * (sfs_random() %
+                           (((Cur_file_ptr->attributes2.size - xfer_size)
+                           / Bytes_per_block) + 1));
+       } else
+           args.offset = 0;
+    }
+
+    /* first write the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block - 1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       args.totalcount = size; /* unused */
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "write: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC_WRITE,
+                               xdr_write, (char *) &args,
+                               xdr_write, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = args.data.data_len;
+           Dump_offset = args.offset;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS_OK) {
+                   Cur_file_ptr->state = Exists;
+                   Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   args.offset += size;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: WRITE %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: write call NFS error %s on file %d\n",
+                               sfs_Myname, nfs2_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                           "%s: write call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for writing max_cnt packets */
+    } /* for buffers and fragments */
+    return(ret);
+
+} /* op_write */
+
+
+static int
+op_create(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    createargs         args;
+    diropres           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[CREATE];
+    ret = 0;
+
+    /* set up the arguments */
+    args.attributes.mode = (0100000 | 0666);   /* 666 NFREG file */
+    args.attributes.uid = Cur_uid;
+    args.attributes.gid = Cur_gid;
+    args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+    args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+    args.attributes.size = 0;
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.where.name = Cur_filename;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_CREATE,
+                       xdr_create, (char *) &args,
+                       xdr_create, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file,
+                       NFS_FHSIZE);
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: create call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: create call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_create */
+
+
+static int
+op_remove(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    diropargs          args;
+    nfsstat            reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[REMOVE];
+    ret = 0;
+
+    /* set up the arguments */
+    args.name = Cur_filename;
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_REMOVE,
+                       xdr_remove, (char *) &args,
+                       xdr_remove, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply == NFS_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: remove call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: remove call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_remove */
+
+
+static int
+op_rename(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target name */
+    renameargs         args;
+    nfsstat            reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[RENAME];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+
+    target_fileinfo_ptr = randfh(RENAME, 0, 0, Nonexistent,
+                                Sfs_non_io_file);
+
+    args.from.name = Cur_file_ptr->file_name;
+    (void) sprintf(target_fileinfo_ptr->file_name, Filespec,
+                  target_fileinfo_ptr->unique_num);
+    args.to.name = target_fileinfo_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_RENAME,
+                       xdr_rename, (char *) &args,
+                       xdr_rename, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply == NFS_OK) {
+           target_fileinfo_ptr->state = Exists;
+           (void) memmove((char *) &target_fileinfo_ptr->fh2,
+                       (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+           target_fileinfo_ptr->attributes2 = Cur_file_ptr->attributes2;
+           target_fileinfo_ptr->size = Cur_file_ptr->size;
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: rename call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rename call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rename */
+
+
+static int
+op_link(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target */
+    linkargs           args;
+    nfsstat            reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[LINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(LINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.from, (char *) &target_fileinfo_ptr->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.to.name = Cur_filename;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_LINK,
+                       xdr_link, (char *) &args,
+                       xdr_link, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply == NFS_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &target_fileinfo_ptr->fh2, NFS_FHSIZE);
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           target_fileinfo_ptr->attributes2.nlink++;
+           Cur_file_ptr->attributes2 = target_fileinfo_ptr->attributes2;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: link call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: link call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_link */
+
+
+static int
+op_symlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target file */
+    symlinkargs                args;
+    nfsstat            reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[SYMLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(SYMLINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.from.name = Cur_filename;
+
+    (void) strcpy(sym_data, "./");
+    (void) strcat(sym_data, target_fileinfo_ptr->file_name);
+    args.attributes.size = strlen(sym_data);
+    args.to = sym_data;
+
+    args.attributes.mode = (0120000 | 0777);
+    args.attributes.uid = Cur_uid;
+    args.attributes.gid = Cur_gid;
+    args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+    args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_SYMLINK,
+                       xdr_symlink, (char *) &args,
+                       xdr_symlink, (char *) &reply,
+                       ((int)Current_test_phase < (int)Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply == NFS_OK) {
+           /*
+            * SYMLINK doesn't return a fh. If we try to
+            * access this symlink (eg, remove(), readlink())
+            * before we do a lookup, we won't have a fh to use.
+            * So, we do a lookup call here.
+            * If it fails, we fill in what we can.
+            */
+           Cur_file_ptr->state = Exists;
+           if (op_lookup() == 0) {
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               Cur_file_ptr->attributes2.type = NFLNK;
+               Cur_file_ptr->attributes2.mode = (0120000|0777);
+               Cur_file_ptr->attributes2.uid = Cur_uid;
+               Cur_file_ptr->attributes2.gid = Cur_gid;
+               Cur_file_ptr->attributes2.atime.seconds =(unsigned int)Cur_time.esec;
+               Cur_file_ptr->attributes2.atime.useconds=(unsigned int)Cur_time.usec;
+               Cur_file_ptr->attributes2.mtime = Cur_file_ptr->attributes2.atime;
+           } else
+               ret++;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: symlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: symlink call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_symlink */
+
+
+static int
+op_mkdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    mkdirargs          args;
+    diropres           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[MKDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    args.attributes.mode = (NFSMODE_DIR | 0777);
+    args.attributes.uid = Cur_uid;
+    args.attributes.gid = Cur_gid;
+    args.attributes.size = (unsigned int) 512;
+    args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+    args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+    args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.where.name = Cur_filename;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_MKDIR,
+                       xdr_mkdir, (char *) &args,
+                       xdr_mkdir, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+           Cur_file_ptr->state = Empty_dir;
+           (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file,
+                       NFS_FHSIZE);
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: mkdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: mkdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_mkdir */
+
+
+static int
+op_rmdir(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    diropargs          args;
+    nfsstat            reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[RMDIR];
+    ret = 0;
+
+    if (Cur_file_ptr->state != Empty_dir) {
+            (void) fprintf(stderr, "%s: Attempting to remove non-Empty_dir %d\n",
+                   sfs_Myname, Cur_file_ptr->unique_num);
+    }
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    args.name = Cur_file_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_RMDIR,
+                       xdr_rmdir, (char *) &args,
+                       xdr_rmdir, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply == NFS_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: rmdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rmdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rmdir */
+
+
+static int
+op_readdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    readdirargs                args;
+    readdirres         reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    uint_t             i;
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+    nfscookie          cookie;
+    bool_t             hit_eof;
+       /* arbitrary fixed ceiling */
+    int                        entry_cnt = SFS_MAXDIRENTS;
+       /* array of entries */
+    entry              entry_stream[SFS_MAXDIRENTS];
+    entry              *entry_ptr;             /* ptr to the dir entry */
+
+    char       name[SFS_MAXNAMLEN];
+       /* array of dir names */
+    char       name_stream[SFS_MAXDIRENTS * SFS_MAXNAMLEN];
+
+
+    /*
+     * 1) need some measure of how many entries are in a directory
+     * currently, we assume SFS_MAXDIRENTS - it should be random
+     * from 0 to MAX for a large MAX we should pre-allocate a buffer for the
+     * returned directory names.
+     * 2) need some measure of how many directory entries to read
+     * during each readdir() call.  Again, we assume SFS_MAXDIRENTS.
+     */
+
+    op_ptr = &Ops[READDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+    (void) memset((char *) args.cookie, '\0', NFS_COOKIESIZE);
+    args.count = DEFAULT_MAX_BUFSIZE;
+
+    /* Have lower layers fill in the data directly.  */
+    reply.readdirres_u.reply.max_entries = entry_cnt;
+    reply.readdirres_u.reply.entries = entry_stream;
+    for (i = 0; i < entry_cnt; i++) {
+       entry_stream[i].name = &name_stream[i * SFS_MAXNAMLEN];
+    }
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_READDIR,
+                       xdr_readdir, (char *) &args,
+                       xdr_readdir, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS_OK) {
+
+           if (DEBUG_CHILD_RPC) {
+               hit_eof = reply.readdirres_u.reply.eof;
+               entry_cnt = reply.readdirres_u.reply.max_entries;
+               entry_ptr = reply.readdirres_u.reply.entries;
+               for (i = 0; i < entry_cnt; i++) {
+                   entry_ptr->name[entry_ptr->name_len] ='\0';
+                   (void) strcpy(name, entry_ptr->name);
+                   (void) memmove((char *) cookie,
+                                       (char *) entry_ptr->cookie,
+                                       NFS_COOKIESIZE);
+                   (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
+                                       sfs_Myname, hit_eof, name);
+                   entry_ptr++;
+               }
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs2_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: readdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readdir */
+
+
+/* Beware - op_statfs() collides w/ some other name, use op_fsstat() */
+static int
+op_fsstat(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    fhandle_t          fh;
+    statfsres          reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[FSSTAT];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC_STATFS,
+                       xdr_statfs, (char *) &fh,
+                       xdr_statfs, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: fsstat call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_fsstat */
+
+
+/*
+ * These are a set of reliable functions used by the initialization code.
+ */
+
+#define LAD_RETRIABLE(stat) (((stat) == RPC_TIMEDOUT) || ((stat) == RPC_CANTDECODERES))
+
+/*
+ * Reliably lookup a file in the current directory
+ * Return:
+ *     -1      RPC error
+ *     1       File doesn't exist
+ *     0       File exists
+ */
+int
+lad_lookup(sfs_fh_type *file_ptr, char *name)
+{
+    diropargs          args;
+    diropres           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_lookup: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+       args.name = name;
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_LOOKUP,
+                       xdr_lookup, (char *) &args,
+                       xdr_lookup, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_lookup(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status == NFSERR_NOENT) {
+       return(1);
+    }
+
+    if (reply.status != NFS_OK) {
+       (void) fprintf(stderr, "lad_lookup(%s) NFS call failed : %s\n",
+                       name, nfs2_strerror(reply.status));
+       return(-1);
+    }
+
+    file_ptr->state = Exists;
+    (void) memmove((char *) &file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
+    (void) strcpy(file_ptr->file_name, name);
+    file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+    file_ptr->size = fh_size(file_ptr);
+
+    return(0);
+}
+
+/*
+ * Reliably remove a file in the current directory
+ */
+int
+lad_remove(sfs_fh_type *file_ptr, char *name)
+{
+    diropargs          args;
+    nfsstat            reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_remove: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does exist
+     */
+    if (file_ptr->attributes2.type == NFDIR)
+       return (lad_rmdir(file_ptr, name));
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.name = name;
+       (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_REMOVE,
+                       xdr_remove, (char *) &args,
+                       xdr_remove, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_remove(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply != NFS_OK) {
+       if (reply != NFSERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_remove(%s) NFS call failed : %s\n",
+                       name, nfs2_strerror(reply));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably remove a directory in the current directory
+ */
+int
+lad_rmdir(sfs_fh_type *file_ptr, char *name)
+{
+    diropargs          args;
+    nfsstat            reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s: lad_rmdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does exist and the directory
+     * is empty.
+     */
+    if (file_ptr->attributes2.type != NFDIR)
+       return (lad_remove(file_ptr, name));
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.name = name;
+       (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_RMDIR,
+                       xdr_remove, (char *) &args,
+                       xdr_remove, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_rmdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply != NFS_OK) {
+       if (reply != NFSERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_rmdir(%s) NFS call failed : %s\n",
+                       name, nfs2_strerror(reply));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably create a symlink in the current directory
+ */
+int
+lad_symlink(sfs_fh_type *file_ptr, char *target, char *name)
+{
+    symlinkargs                args;
+    nfsstat            reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_symlink: %lx %s -> %s\n", sfs_Myname,
+                       (int32_t) file_ptr, name, target);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.from.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+       args.from.name = name;
+
+       (void) strcpy(sym_data, "./");
+       (void) strcat(sym_data, target);
+       args.attributes.size = strlen(sym_data);
+       args.to = sym_data;
+
+       args.attributes.mode = (0120000 | 0777);
+       args.attributes.uid = Cur_uid;
+       args.attributes.gid = Cur_gid;
+       args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+       args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_SYMLINK,
+                       xdr_symlink, (char *) &args,
+                       xdr_symlink, (char *) &reply,
+                       Nfs_timers[Init]);
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_symlink(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply != NFS_OK) {
+       if (reply != NFSERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_symlink(%s, %s) NFS call failed : %s\n",
+                       target, name, nfs2_strerror(reply));
+           return(-1);
+       }
+    }
+
+    /*
+     * SYMLINK doesn't return a fh. If we try to
+     * access this symlink (eg, remove(), readlink())
+     * before we do a lookup, we won't have a fh to use.
+     * So, we do a lookup call here.
+     * If it fails, we fill in what we can.
+     */
+    return (lad_lookup(file_ptr, name));
+}
+
+/*
+ * Reliably create a directory in the current directory
+ */
+int
+lad_mkdir(sfs_fh_type *file_ptr, char *name)
+{
+    mkdirargs          args;
+    diropres           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_mkdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.attributes.mode = (NFSMODE_DIR | 0777);
+       args.attributes.uid = Cur_uid;
+       args.attributes.gid = Cur_gid;
+       args.attributes.size = (unsigned int) 512;
+       args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+       args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+       args.where.name = name;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_MKDIR,
+                       xdr_mkdir, (char *) &args,
+                       xdr_mkdir, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_mkdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFSERR_EXIST)
+       return(1);
+
+    if (reply.status != NFS_OK) {
+       if (reply.status != NFSERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_mkdir(%s) NFS call failed : %s\n",
+                       name, nfs2_strerror(reply.status));
+           return(-1);
+       }
+       /*
+        * If the first mkdir suceeded but the reply as dropped and
+        * was retransmitted, we still need to lookup the attributes
+        */
+       if (lad_lookup(file_ptr, name))
+          return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file,
+                       NFS_FHSIZE);
+       (void) strcpy(file_ptr->file_name, name);
+       file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+       file_ptr->size = fh_size(file_ptr);
+    }
+    file_ptr->state = Empty_dir;
+
+    return(0);
+}
+
+/*
+ * Reliably write a file in the current directory
+ */
+int
+lad_write(sfs_fh_type *file_ptr, int32_t offset, int32_t length)
+{
+    static char                        *buf = NULL;    /* the data buffer */
+    int32_t                    size;           /* size of data write */
+    int32_t                    cur_cnt;
+    writeargs                  args;
+    attrstat                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_write: %lx[%lx] %ld %ld\n",
+                       sfs_Myname, (int32_t) file_ptr, (int32_t) file_ptr->dir,
+                       offset, length);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does exist
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &file_ptr->fh2,
+                       NFS_FHSIZE);
+    args.beginoffset = 0;      /* unused */
+    args.offset = offset;
+
+    size = Bytes_per_block;
+    for (cur_cnt = 0; cur_cnt < length; cur_cnt += size) {
+       if ((cur_cnt + size) > length)
+               size = length - cur_cnt;
+
+       if (size == 0)
+           break;
+
+       args.totalcount = size; /* unused */
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* make the call now */
+        /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_WRITE,
+                               xdr_write, (char *) &args,
+                               xdr_write, (char *) &reply,
+                               Nfs_timers[Init]);
+
+           if (rpc_stat == RPC_SUCCESS) 
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_write() RPC call failed : %s\n",
+                               clnt_sperrno(rpc_stat));
+           }
+           if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+           }
+       }
+       if (reply.status != NFS_OK) {
+           (void) fprintf(stderr, "lad_write() NFS call failed : %s\n",
+                       nfs2_strerror(reply.status));
+           return(-1);
+       }
+       file_ptr->state = Exists;
+       file_ptr->attributes2 = reply.attrstat_u.attributes;
+       file_ptr->size = fh_size(file_ptr);
+       args.offset += size;
+    }
+    return(0);
+}
+
+/*
+ * Reliably create a file in the current directory
+ */
+int
+lad_create(sfs_fh_type *file_ptr, char *name)
+{
+    createargs         args;
+    diropres           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_create: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.attributes.mode = (0100000 | 0666);        /* 666 NFREG file */
+       args.attributes.uid = Cur_uid;
+       args.attributes.gid = Cur_gid;
+       args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+       args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+       args.attributes.size = 0;
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh2,
+                       NFS_FHSIZE);
+       args.where.name = name;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_CREATE,
+                       xdr_create, (char *) &args,
+                       xdr_create, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_create(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFSERR_EXIST) {
+       return(1);
+    }
+
+    if (reply.status != NFS_OK) {
+       if (reply.status != NFSERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_create(%s) NFS call failed : %s\n",
+                       name, nfs2_strerror(reply.status));
+           return(-1);
+       }
+       /*
+        * If the first create suceeded but the reply as dropped and
+        * was retransmitted, we still need to lookup the attributes
+        */
+       if (lad_lookup(file_ptr, name))
+          return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
+       (void) strcpy(file_ptr->file_name, name);
+       file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
+       file_ptr->size = fh_size(file_ptr);
+    }
+
+    file_ptr->state = Exists;
+    /*
+     * Directories are created as Empty_dir, when a file is created it
+     * becomes an Exists.
+     */
+    file_ptr->dir->state = Exists;
+
+    return(0);
+}
+
+/*
+ * Reliably set the size of a file in the current directory
+ */
+int
+lad_truncate(sfs_fh_type *file_ptr, int32_t size)
+{
+    sattrargs          args;
+    attrstat           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_truncate: %lx[%lx] %ld\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, size);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name already exists
+     */
+    /* CONSTCOND */
+    while (1) {
+       /*
+        * set up the arguments
+        * Set the mode and times as well
+        */
+       args.attributes.mode = 0666;
+       args.attributes.uid = (unsigned int) -1;
+       args.attributes.gid = (unsigned int) -1;
+       args.attributes.size = (unsigned int) -1;
+       args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+       args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+       args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+       (void) memmove((char *) &args.file, (char *) &file_ptr->fh2,
+                       NFS_FHSIZE);
+       args.attributes.size = (unsigned int) size;
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC_SETATTR,
+                       xdr_setattr, (char *) &args,
+                       xdr_setattr, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr,
+                               "lad_truncate(%ld) RPC call failed : %s\n",
+                               size, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status != NFS_OK) {
+       (void) fprintf(stderr, "lad_truncate(%ld) NFS call failed : %s\n",
+                       size, nfs2_strerror(reply.status));
+       return(-1);
+    }
+    file_ptr->attributes2 = reply.attrstat_u.attributes;
+    file_ptr->size = fh_size(file_ptr);
+
+    return(0);
+}
+
+static char *
+nfs2_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFSERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFSERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFSERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFSERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFSERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFSERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFSERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFSERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFSERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFSERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFSERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFSERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFSERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFSERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFSERR_OPNOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFSERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFSERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFSERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFSERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFSERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFSERR_WFLUSH:
+           (void) strcpy(str, "write cache flushed");
+           break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+/* sfs_c_ops.c */
diff --git a/TBBT/trace_play/sfs_2_vld.c b/TBBT/trace_play/sfs_2_vld.c
new file mode 100644 (file)
index 0000000..45e24d9
--- /dev/null
@@ -0,0 +1,1747 @@
+#ifndef lint
+static char sfs_c_vldSid[] = "@(#)sfs_2_vld.c 2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *      Copyright 1991,1992  Legato Systems, Inc.                *
+ *      Copyright 1991,1992  Auspex Systems, Inc.                *
+ *      Copyright 1991,1992  Data General Corporation            *
+ *      Copyright 1991,1992  Digital Equipment Corporation       *
+ *      Copyright 1991,1992  Interphase Corporation              *
+ *      Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ------------------------------ sfs_c_vld.c ---------------------------
+ *
+ * Validation suite for sfs.
+ *
+ *.Exported_routines
+ *      void Validate_ops(int, char **)
+ *
+ *.Local_routines
+ *      void validate_init_rpc()
+ *      void validate_creation(void)
+ *      void validate_attributes(void)
+ *      void validate_read_write(void)
+ *      void validate_rename(void)
+ *      int compare_sattr(char *, char *, sattr *, fattr *)
+ *      int compare_fattr(char *, char *, fattr *, fattr *)
+ *      uint16_t sum(unsigned char *, uint_t)
+ *      void validate_remove(void)
+ *      void validate_cleanup(void)
+ *      void validate_exit(void)
+ *      void verror(int, ValMsgType, char *, ...)
+ *
+ *.Revision History
+ *      04-Dec-91       Keith           Define string.h for SYSV/SVR4.
+ *      25-Jun-91       Wiryaman        Created
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+extern struct hostent  *Server_hostent;
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+
+/* forward definitions for local routines */
+/*
+ * validate options
+ * BATCH        - do complete pass of validation, reporting errors if any
+ * VERBOSE      - prints step-by-step validation actions being performed
+ * INTERACTIVE  - VERBOSE and if any errors encountered, ask to continue
+ *                validation or not.
+ */
+#define VAL_BATCH       1
+#define VAL_VERBOSE     2
+#define VAL_INTERACTIVE 3
+
+typedef enum {
+        I = 1,
+        W = 2,
+        E = 3
+} ValMsgType;
+
+#define NUMREGFILES     7
+#define NUMDIRS         5
+#define NUMLINKS        5
+#define NUMSYMLINKS     5
+#define NUMFILES        NUMREGFILES + NUMDIRS + NUMLINKS + NUMSYMLINKS
+#define NUMFRAGS        8
+
+static void validate_init_rpc(void);
+static void validate_exit(void);
+static void validate_creation(void);
+static void validate_attributes(void);
+static void validate_read_write(void);
+static void validate_rename(void);
+static void validate_remove(void);
+static void validate_cleanup(void);
+static int compare_sattr(char *, char *, sattr *, fattr *);
+static int compare_fattr(char *, char *, fattr *, fattr *);
+static uint16_t sum(unsigned char *, uint_t);
+static void verror(int, ValMsgType, char *, ...);
+
+static void val_op_null(void);
+static void val_op_getattr(fhandle_t *, attrstat *);
+static void val_op_setattr(sattrargs *, attrstat *);
+static void val_op_lookup(diropargs *, diropres *);
+static void val_op_readlink(fhandle_t *, readlinkres *);
+static void val_op_read(readargs *, readres *);
+static void val_op_write(writeargs *, attrstat *);
+static void val_op_create(createargs *, diropres *);
+static void val_op_remove(diropargs *, nfsstat *);
+static void val_op_rename(renameargs *, nfsstat *);
+static void val_op_link(linkargs *, nfsstat *);
+static void val_op_symlink(symlinkargs *, nfsstat *);
+static void val_op_mkdir(mkdirargs *, diropres *);
+static void val_op_rmdir(diropargs *, nfsstat *);
+static void val_op_readdir(readdirargs *, readdirres *);
+static void val_op_statfs(fhandle_t *, statfsres *);
+static void create_tmp_handles(void);
+static void delete_tmp_handles(void);
+
+/*
+ * ----------------------  Static Declarations ----------------------
+ */
+
+int Validate;
+
+static int Validate_errors = 0;
+static char Testdirname[SFS_MAXPATHLEN];    /* test dir component name */
+
+/*
+ * ----------------------  SFS Validation Suite  ----------------------
+ */
+
+void
+Validate_ops(
+    int         argc,
+    char *      argv[])
+{
+    char *      valdir;
+    CLIENT *    mount_client_ptr;
+
+    if (argc > 1) {
+        verror(VAL_BATCH, E, "Can only validate one directory at a time.\n");
+        exit(1);
+    }
+
+    Num_io_files = NUMFILES;
+    Cur_uid = Real_uid;
+    nfs_version = NFS_VERSION;
+
+    if (argc == 0)
+        valdir = ".";
+    else
+        valdir = argv++[0];
+
+    (void) sprintf(Testdirname, "%s/validatedir", valdir);
+
+    do {
+        verror(VAL_BATCH, I, "validating sfs on \"%s\" directory ...\n",
+                valdir);
+
+        init_fileinfo();
+       create_tmp_handles();
+
+        /*
+         * need priv port to do following
+         */
+        mount_client_ptr = lad_getmnt_hand(valdir);
+        if (mount_client_ptr == NULL) {
+            exit(1);
+        }
+        validate_init_rpc();
+
+        /*
+         * should be all done doing priv port stuff
+         */
+        if (setuid(Real_uid) != 0) {
+           (void) fprintf(stderr,"%s: %s%s\n",
+                   sfs_Myname, "cannot perform setuid operation.\n",
+                   "Do `make install` as root.\n");
+        }
+
+        init_mount_point(0, valdir, mount_client_ptr);
+        verror(VAL_VERBOSE, I, "validating null operation ...\n");
+        val_op_null();
+
+        validate_creation();
+        validate_attributes();
+        validate_read_write();
+        validate_rename();
+        validate_remove();
+        argc--;
+        valdir = argv++[0];
+
+        /*
+         * Cleanup mount client handle
+         */
+        clnt_destroy(mount_client_ptr);
+
+       delete_tmp_handles();
+        validate_cleanup();
+
+    } while (argc > 0);
+
+    validate_exit();
+
+} /* Validate_ops */
+
+
+/*
+ * allocate and initialize client handles
+ */
+static void
+validate_init_rpc(void)
+{
+       NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                        (uint32_t) NFS_PROGRAM,
+                                        (uint32_t) NFS_VERSION,
+                                        RPC_ANYSOCK, &Nfs_timers[0]);
+       if (NFS_client == ((CLIENT *) NULL)) { 
+               verror(VAL_BATCH, E, "portmap/nfsd server not responding\n"); 
+               exit(1); 
+       }
+       NFS_client->cl_auth = authunix_create(lad_hostname, Real_uid,
+                                      Cur_gid, 0, NULL);
+} /* validate_init_rpc */
+
+
+static void
+validate_creation(void)
+{
+    int                 filenum;
+    int                 target_filenum;
+    diropargs           arglp;
+    createargs          argcr;
+    mkdirargs           argmk;
+    linkargs            argln;
+    symlinkargs         argsl;
+    char                sl_target_path[NFS_MAXPATHLEN];
+    diropres            reply;
+    readlinkres         rlreply;
+    char                sym_data[NFS_MAXPATHLEN];
+
+    for (filenum=0; filenum < NUMFILES ; filenum++) {
+
+        Cur_file_ptr = &Io_files[filenum];
+        sfs_gettime(&Cur_time);
+
+        if (filenum < NUMREGFILES) {
+
+            (void) sprintf(Cur_filename, Filespec, filenum);
+
+            /* regular file creation */
+            argcr.attributes.mode= (NFSMODE_REG | 0666);
+            argcr.attributes.uid = Cur_uid;
+            argcr.attributes.gid = Cur_gid;
+            argcr.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+            argcr.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+            argcr.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+            argcr.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+            argcr.attributes.size = 0;
+            (void) memmove((char *) &argcr.where.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+            argcr.where.name = Cur_filename;
+
+            verror(VAL_VERBOSE, I, "validating create file %s ...\n",
+                                       Cur_filename);
+            val_op_create(&argcr, &reply);
+
+            if (reply.status == NFS_OK) {
+                Cur_file_ptr->state = Exists;
+                (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
+                (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+                (void) memmove((char *) &Cur_file_ptr->attributes2,
+                               (char *) &reply.diropres_u.diropres.attributes,
+                               sizeof(Cur_file_ptr->attributes2));
+                (void) compare_sattr(Ops[CREATE].name, Io_files[filenum].file_name,
+                            &argcr.attributes, &Cur_file_ptr->attributes2);
+            } else {
+                Cur_file_ptr->state = Nonexistent;
+                errno = (int)reply.status;
+                verror(VAL_BATCH, E, "create %s failed: %m\n", Cur_filename);
+                /*
+                 * An error in file creation is fatal, because we use the
+                 * created files to validate the other operations.
+                 */
+                validate_exit();
+            }
+
+        } else if (filenum < NUMREGFILES + NUMDIRS) {
+
+            (void) sprintf(Cur_filename, Dirspec, filenum);
+
+            /* directory creation */
+            argmk.attributes.mode= (NFSMODE_DIR | 0777);
+            argmk.attributes.uid = Cur_uid;
+            argmk.attributes.gid = Cur_gid;
+            argmk.attributes.size = 0xFFFFFFFF;
+            argmk.attributes.atime.seconds = (unsigned int) Cur_time.esec;
+            argmk.attributes.atime.useconds = (unsigned int) Cur_time.usec;
+            argmk.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
+            argmk.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
+            (void) memmove((char *) &argmk.where.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+            argmk.where.name = Cur_filename;
+
+            verror(VAL_VERBOSE, I, "validating mkdir %s ...\n", Cur_filename);
+            val_op_mkdir(&argmk, &reply);
+
+            if (reply.status == NFS_OK) {
+                Cur_file_ptr->state = Exists;
+                (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file,
+                       NFS_FHSIZE);
+                (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+                (void) memmove((char *) &Cur_file_ptr->attributes2,
+                               (char *) &reply.diropres_u.diropres.attributes,
+                               sizeof(Cur_file_ptr->attributes2));
+                (void) compare_sattr(Ops[MKDIR].name, Io_files[filenum].file_name,
+                                &argmk.attributes, &Cur_file_ptr->attributes2);
+            } else {
+                Cur_file_ptr->state = Nonexistent;
+                verror(VAL_BATCH, W, "mkdir %s failed:%m\n", Cur_filename);
+            }
+
+        } else if(filenum < NUMREGFILES + NUMDIRS + NUMLINKS ) {
+
+            (void) sprintf(Cur_filename, Filespec, filenum);
+
+            /* hard link creation */
+            target_filenum = NUMFILES-NUMSYMLINKS-1-filenum;
+            (void) memmove((char *) &argln.from,
+                       (char *) &Io_files[target_filenum].fh2, NFS_FHSIZE);
+            (void) memmove((char *) &argln.to.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+            argln.to.name = Cur_filename;
+
+            verror(VAL_VERBOSE, I, "validating link %s %s ...\n",
+                               Io_files[target_filenum].file_name, Cur_filename);
+            val_op_link(&argln, &reply.status);
+
+            if (reply.status == NFS_OK) {
+                Cur_file_ptr->state = Exists;
+                (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &Io_files[target_filenum].fh2,
+                       NFS_FHSIZE);
+                (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+                Cur_file_ptr->attributes2 = Io_files[target_filenum].attributes2;
+                Io_files[target_filenum].attributes2.nlink++;
+                Cur_file_ptr->attributes2.nlink++;
+            } else {
+                Cur_file_ptr->state = Nonexistent;
+                verror(VAL_BATCH, W, "link %s failed: %m\n", Cur_filename);
+            }
+
+        } else {
+
+            (void) sprintf(Cur_filename, Symspec, filenum);
+
+            /* symbolic link creation */
+            target_filenum = NUMFILES-1-filenum;
+            (void) memmove((char *) &argsl.from.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+            argsl.from.name = Cur_filename;
+            (void) sprintf(sl_target_path,
+                           "./%s", Io_files[target_filenum].file_name);
+            argsl.attributes.size = strlen(sl_target_path);
+            argsl.to = sl_target_path;
+            argsl.attributes.mode = (NFSMODE_LNK | 0777);
+            argsl.attributes.uid = Cur_uid;
+            argsl.attributes.gid = Cur_gid;
+            argsl.attributes.atime.seconds = (unsigned int)Cur_time.esec;
+            argsl.attributes.atime.useconds = (unsigned int)Cur_time.usec;
+            argsl.attributes.mtime.seconds = (unsigned int)Cur_time.esec;
+            argsl.attributes.mtime.useconds = (unsigned int)Cur_time.usec;
+
+            verror(VAL_VERBOSE, I, "validating symlink %s %s ...\n",
+                                       sl_target_path, Cur_filename);
+            val_op_symlink(&argsl, &reply.status);
+
+            if (reply.status == NFS_OK) {
+                Cur_file_ptr->state = Exists;
+
+                /* do a lookup to get file handle and attributes */
+                (void) memmove((char *) &arglp.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+                arglp.name = Cur_filename;
+
+                val_op_lookup(&arglp, &reply);
+
+                if (reply.status == NFS_OK) {
+                    (void) memmove((char *) &Cur_file_ptr->fh2,
+                       (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
+                    (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+                    Cur_file_ptr->attributes2 =
+                                        reply.diropres_u.diropres.attributes;
+                    (void) compare_sattr(Ops[SYMLINK].name,
+                                        Io_files[filenum].file_name,
+                                        &argsl.attributes,
+                                        &Cur_file_ptr->attributes2);
+                } else {
+                    verror(VAL_BATCH, W, "lookup %s failed: %m\n",
+                                               Cur_filename);
+                    continue;
+                }
+
+                /* validate readlink */
+                rlreply.readlinkres_u.data = sym_data;
+
+                verror(VAL_VERBOSE, I, "validating readlink %s ...\n",
+                                               Cur_filename);
+                val_op_readlink(&Cur_file_ptr->fh2, &rlreply);
+
+                if (rlreply.status == NFS_OK) {
+                    sym_data[rlreply.readlinkres_u.len] = '\0';
+                    if (strcmp(sl_target_path, sym_data)) {
+                        verror(VAL_BATCH, W,
+                            "readlink %s error, result = %s, should be %s\n",
+                            Cur_filename, rlreply.readlinkres_u.data,
+                            sl_target_path);
+                    }
+                } else {
+                    verror(VAL_BATCH, W, "readlink %s failed:%m\n",
+                            Cur_filename);
+                }
+
+            } else {
+                Cur_file_ptr->state = Nonexistent;
+                verror(VAL_BATCH, W, "symlink %s failed: %m\n",
+                        Cur_filename);
+            }
+        }
+    } /* end for each file */
+
+} /* validate_creation */
+
+
+static void
+validate_attributes(void)
+{
+    int                 filenum;
+    diropargs           arglp;
+    diropres            lreply;
+    fhandle_t           fh;
+    sattrargs           argsa;
+    attrstat            areply;
+
+    /* validate fsstat */
+
+    /* validate lookup */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+        (void) memmove((char *) &arglp.dir, (char *) &Export_dir.fh2,
+                       NFS_FHSIZE);
+        arglp.name = Io_files[filenum].file_name;
+
+        verror(VAL_VERBOSE, I, "validating lookup %s ...\n",
+                Io_files[filenum].file_name);
+        val_op_lookup(&arglp, &lreply);
+
+        if (lreply.status == NFS_OK) {
+            if (memcmp((char *) &(Io_files[filenum].fh2),
+                     (char *) &(lreply.diropres_u.diropres.file),
+                        NFS_FHSIZE)) {
+                verror(VAL_BATCH, W, "lookup %s: file handle mismatch\n",
+                        Io_files[filenum].file_name);
+            }
+            (void) compare_fattr(Ops[LOOKUP].name, Io_files[filenum].file_name,
+                          &Io_files[filenum].attributes2,
+                          &lreply.diropres_u.diropres.attributes);
+        } else {
+            verror(VAL_BATCH, W, "lookup %s failed:%m\n",
+                    Io_files[filenum].file_name);
+        }
+    }
+
+    /* validate getattr */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+        (void) memmove((char *) &fh, (char *) &Io_files[filenum].fh2,
+                       NFS_FHSIZE);
+
+        verror(VAL_VERBOSE, I, "validating getattr %s ...\n",
+                Io_files[filenum].file_name);
+        val_op_getattr(&fh, &areply);
+
+        if (areply.status == NFS_OK) {
+            (void) compare_fattr(Ops[GETATTR].name, Io_files[filenum].file_name,
+                          &Io_files[filenum].attributes2,
+                          &areply.attrstat_u.attributes);
+        } else {
+            verror(VAL_BATCH, W, "getattr %s failed: %m\n",
+                    Io_files[filenum].file_name);
+        }
+    }
+
+    /*validate setattr */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+        sfs_gettime(&Cur_time);
+        if (filenum >= NUMREGFILES && filenum < NUMREGFILES + NUMDIRS)
+          argsa.attributes.mode= 0777;
+        else
+          argsa.attributes.mode= 0666;
+        argsa.attributes.uid  = 0xFFFFFFFF;
+        argsa.attributes.gid  = 0xFFFFFFFF;
+        argsa.attributes.size = 0xFFFFFFFF;
+        argsa.attributes.atime.seconds =  (unsigned int)Cur_time.esec;
+        argsa.attributes.atime.useconds = (unsigned int)Cur_time.usec;
+        argsa.attributes.mtime.seconds =  (unsigned int)Cur_time.esec;
+        argsa.attributes.mtime.useconds = (unsigned int)Cur_time.usec;
+        (void) memmove((char *) &argsa.file, (char *) &Io_files[filenum].fh2,
+                       NFS_FHSIZE);
+
+        verror(VAL_VERBOSE, I, "validating setattr %s ...\n",
+                Io_files[filenum].file_name);
+        val_op_setattr(&argsa, &areply);
+
+        if (areply.status == NFS_OK) {
+            if (argsa.attributes.mode != areply.attrstat_u.attributes.mode){
+                argsa.attributes.mode |=
+                        (Io_files[filenum].attributes2.mode & NFSMODE_FMT);
+                argsa.attributes.mode &= Io_files[filenum].attributes2.mode;
+            }
+            Io_files[filenum].attributes2 = areply.attrstat_u.attributes;
+            (void) compare_sattr(Ops[SETATTR].name, Io_files[filenum].file_name,
+                          &argsa.attributes, &areply.attrstat_u.attributes);
+
+            val_op_getattr(&argsa.file, &areply);
+
+            if (areply.status == NFS_OK) {
+                (void) compare_fattr(Ops[GETATTR].name, Io_files[filenum].file_name,
+                              &Io_files[filenum].attributes2,
+                              &areply.attrstat_u.attributes);
+            } else {
+                verror(VAL_BATCH, W, "getattr %s failed: %m\n",
+                        Io_files[filenum].file_name);
+            }
+        } else {
+            verror(VAL_BATCH, W, "setattr %s failed: %m\n",
+                    Io_files[filenum].file_name);
+        }
+    }
+
+} /* validate_attributes */
+
+
+static void
+validate_read_write(void)
+{
+    struct {
+        uint16_t  sum;                    /* checksum of data */
+        uint16_t  len;                    /* length of len and data */
+        char            data[DEFAULT_MAX_BUFSIZE - 2 * sizeof(uint16_t)];
+    } block;
+    writeargs           argwr;
+    attrstat            wrreply;
+    readargs            argrd;
+    readres             rdreply;
+    int                 maxblks;
+    int                 maxfiles;
+    uint_t             i;
+    int                 numfiles;
+    int                 filenum;
+    int                 blocknum;
+    readdirargs         argrdir;
+    readdirres          rdirreply;
+    int                 entry_cnt = 9;
+    entry               entry_stream[9];
+    char                name_stream[9 * SFS_MAXNAMLEN];
+
+    /* validate write */
+
+    /* get the maximum number of blocks sfs will write */
+    maxblks = Io_dist_ptr->max_bufs;
+    maxfiles = maxblks > NUMREGFILES ? NUMREGFILES : maxblks;
+
+    /* write maxblks - filenum + 1 blocks to each regular file */
+    argwr.offset = 0;
+    argwr.beginoffset = 0; /* unused */
+    argwr.totalcount = 0; /* unused */
+    argwr.data.data_val = (char *)&block;
+
+    for (blocknum = 0; blocknum <= maxblks ; blocknum++) {
+
+        for (i=0; i < sizeof(block.data); i++)
+            block.data[i] = (char)blocknum;
+
+        for (filenum=0; filenum < maxfiles; filenum++) {
+
+            /* Write fewer blocks to files with higher numbers. */
+            if (blocknum > (maxblks - filenum))
+                break;
+
+            /* set the length field */
+            if (blocknum == (maxblks - filenum)) {
+                block.len = ((maxfiles - filenum) *
+                            (Bytes_per_block/Kb_per_block)) - (sizeof(block.len)
+                             + sizeof(block.sum));
+            } else {
+                block.len = Bytes_per_block - (sizeof(block.len)
+                            + sizeof(block.sum));
+            }
+            block.sum = sum((unsigned char *) &block.len,
+                            block.len + sizeof(block.len));
+
+            (void) memmove((char *) &argwr.file,
+                       (char *) &Io_files[filenum].fh2, NFS_FHSIZE);
+            argwr.data.data_len = block.len +
+                                  sizeof(block.len) + sizeof(block.sum);
+
+            verror(VAL_VERBOSE, I,
+                    "validating write %d bytes @ offset %d to %s ...\n",
+                    argwr.data.data_len, argwr.offset,
+                    Io_files[filenum].file_name);
+
+            val_op_write(&argwr, &wrreply);
+
+            if (wrreply.status == NFS_OK) {
+                (void) compare_fattr(Ops[WRITE].name, Io_files[filenum].file_name,
+                              &Io_files[filenum].attributes2,
+                              &wrreply.attrstat_u.attributes);
+                Io_files[filenum].attributes2 = wrreply.attrstat_u.attributes;
+            } else {
+                verror(VAL_BATCH, W, "write %s failed: %m\n",
+                        Io_files[filenum].file_name);
+            }
+        }
+        argwr.offset += Bytes_per_block;
+    }
+
+    /* validate read */
+
+    for (filenum = 0; filenum < maxfiles; filenum++) {
+        (void) memmove((char *) &argrd.file, (char *) &Io_files[filenum].fh2,
+                       NFS_FHSIZE);
+        argrd.offset = 0;
+        argrd.count = 0;
+        rdreply.readres_u.reply.data.data_len = 0;
+        maxblks = Io_files[filenum].attributes2.size / Bytes_per_block;
+        for (blocknum = 0; blocknum <= maxblks; blocknum ++) {
+
+            if (argrd.count != rdreply.readres_u.reply.data.data_len) {
+                argrd.count -= rdreply.readres_u.reply.data.data_len;
+                rdreply.readres_u.reply.data.data_val = (char *)&block +
+                                        rdreply.readres_u.reply.data.data_len;
+                blocknum--;
+            } else {
+                if (blocknum < maxblks)
+                    argrd.count = Bytes_per_block;
+                else
+                    argrd.count = (maxfiles - filenum)
+                                  * (Bytes_per_block/Kb_per_block);
+                rdreply.readres_u.reply.data.data_val = (char *)&block;
+            }
+            argrd.totalcount = argrd.count; /* unused */
+
+            verror(VAL_VERBOSE, I,
+                   "validating read %d bytes @ offset %d from %s ...\n",
+                    argrd.count, argrd.offset,
+                    Io_files[filenum].file_name);
+
+            val_op_read(&argrd, &rdreply);
+
+            if (rdreply.status == NFS_OK) {
+                (void) compare_fattr(Ops[READ].name, Io_files[filenum].file_name,
+                              &Io_files[filenum].attributes2,
+                              &rdreply.readres_u.reply.attributes);
+                Io_files[filenum].attributes2 =
+                                        rdreply.readres_u.reply.attributes;
+                argrd.offset += rdreply.readres_u.reply.data.data_len;
+            } else {
+                verror(VAL_BATCH, W, "read %s failed: %m\n",
+                        Io_files[filenum].file_name);
+            }
+
+            if (argrd.count ==
+                (block.sum != sum((unsigned char *) &block.len,
+                                  block.len + sizeof(block.len)))) {
+                verror(VAL_BATCH, W, "read %s checksum mismatch\n",
+                        Io_files[filenum].file_name);
+            }
+        }
+    }
+
+    /* validate readdir */
+    numfiles = 0;
+
+    (void) memmove((char *) &argrdir.dir, (char *) &Export_dir.fh2, NFS_FHSIZE);
+    (void) memset((char *) argrdir.cookie, '\0', NFS_COOKIESIZE);
+    argrdir.count = DEFAULT_MAX_BUFSIZE;
+
+    (void) memset((char *) &rdirreply, '\0', sizeof(rdirreply));
+    rdirreply.readdirres_u.reply.max_entries = entry_cnt;
+    rdirreply.readdirres_u.reply.entries = entry_stream;
+    for (i = 0; i < entry_cnt; i++) {
+        entry_stream[i].name = &name_stream[i * SFS_MAXNAMLEN];
+    }
+
+    do {
+        verror(VAL_VERBOSE, I, "validating readdir %d entries of %s ...\n",
+                rdirreply.readdirres_u.reply.max_entries, Testdirname);
+        val_op_readdir(&argrdir, &rdirreply);
+
+        if (rdirreply.status == NFS_OK) {
+            for (i = 0; i < rdirreply.readdirres_u.reply.max_entries; i++) {
+                numfiles++;
+                entry_stream[i].name[entry_stream[i].name_len] = '\0';
+                if (!entry_stream[i].valid) {
+                    verror(VAL_BATCH, W,
+                          "readdir %s error: entry %d (%s) is marked invalid\n",
+                            Testdirname, i, entry_stream[i].name);
+                }
+                if ((!strcmp(entry_stream[i].name, ".")) ||
+                    (!strcmp(entry_stream[i].name, "..")) ) {
+                    numfiles--;
+                    continue;
+                }
+                for (filenum = 0; filenum < NUMFILES; filenum++) {
+                    if (!strcmp(entry_stream[i].name, Io_files[filenum].file_name)) {
+                        if (entry_stream[i].fileid !=
+                                    Io_files[filenum].attributes2.fileid) {
+                            verror(VAL_BATCH, E,
+                                  "readdir %s error: file %s fileid mismatch\n",
+                                    Testdirname, entry_stream[i].name);
+
+                            verror(VAL_BATCH, W,
+                                   "   fileid: got = %d, original = %d\n",
+                                    entry_stream[i].fileid,
+                                   Io_files[filenum].attributes2.fileid);
+                        }
+                        break;
+                    }
+                }
+                if (filenum == NUMFILES) {
+                    verror(VAL_BATCH, W,
+               "readdir %s error: file \"%s\" was not created within sfs\n",
+                            Testdirname, entry_stream[i].name);
+                }
+            }
+
+            if (i < entry_cnt && entry_stream[i].valid) {
+                verror(VAL_BATCH, W,
+                        "readdir %s error: valid entries exceeded maximum\n",
+                        Testdirname);
+            }
+
+        } else {
+            verror(VAL_BATCH, W, "readdir %s failed: %m\n", Testdirname);
+        }
+
+        (void) memmove((char *)argrdir.cookie,
+        (char *)entry_stream[rdirreply.readdirres_u.reply.max_entries-1].cookie,
+                       NFS_COOKIESIZE);
+
+    } while (rdirreply.readdirres_u.reply.eof == 0);
+
+    if (numfiles != NUMFILES) {
+        verror(VAL_BATCH, W,
+                        "readdir %s error: the number of files found\n\
+does not match with the number of files created within sfs\n", Testdirname);
+    }
+
+} /* validate_read_write */
+
+
+static void
+validate_rename(void)
+{
+    renameargs  argrn;
+    nfsstat     rnreply;
+    int         filenum;
+    char        newname[SFS_MAXNAMLEN];
+    int         rncount = 0;
+
+    (void) memmove((char *) &argrn.from.dir, (char *) &Export_dir.fh2, NFS_FHSIZE);
+    (void) memmove((char *) &argrn.to.dir, (char *) &Export_dir.fh2, NFS_FHSIZE);
+
+    for (filenum=0; filenum < NUMFILES; filenum++) {
+        if (Io_files[filenum].state != Exists)
+            continue;
+
+        rncount++;
+        (void) sprintf(newname, "n%s", Io_files[filenum].file_name);
+        argrn.from.name = Io_files[filenum].file_name;
+        argrn.to.name = newname;
+
+        verror(VAL_VERBOSE, I, "validating rename %s %s ...\n",
+                argrn.from.name, argrn.to.name);
+
+        val_op_rename(&argrn, &rnreply);
+
+        if (rnreply == NFS_OK) {
+            (void) strcpy(Io_files[filenum].file_name, newname);
+        } else {
+            verror(VAL_BATCH, W, "rename %s to %s failed: %m\n",
+                    Io_files[filenum].file_name, newname);
+        }
+
+    }
+
+    if (!rncount) {
+        verror(VAL_BATCH, E, "validate_rename: no files renamed\n");
+        verror(VAL_BATCH, W, "    due to previous operation error\n");
+    }
+
+} /* validate_rename */
+
+
+static int
+compare_fattr(
+    char *      op,
+    char *      fname,
+    fattr *     attr1,
+    fattr *     attr2)
+{
+    int         ret = TRUE;
+    int         prev_warn = FALSE; /* -1 info warning */
+    int         flag_error = FALSE;
+
+    if (attr1->type != attr2->type) {
+        if (attr1->type == 0xFFFFFFFF) {
+            prev_warn = TRUE;
+            if (ret) {
+                verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                    fname, op);
+            }
+            verror(VAL_BATCH, I, "    type: current = %d, previous =  %d\n",
+                   attr2->type, attr1->type);
+            attr1->type = attr2->type;
+            ret = FALSE;
+        }
+        else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    type: current = %d, previous =  %d\n",
+                        attr2->type, attr1->type);
+                ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if ((attr1->mode & NFSMODE_MASK) != (attr2->mode & NFSMODE_MASK)) {
+        if (attr1->mode == (unsigned int)0xFFFFFFFF) {
+                prev_warn = TRUE;
+                if (ret) {
+                        verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                                fname, op);
+                }
+                verror(VAL_BATCH, I, "    mode: current = %7o, previous =  %7o\n",
+                        attr2->mode, attr1->mode);
+                attr1->mode =  attr2->mode;
+                ret = FALSE;
+        }
+        else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    mode: current = %d, previous =  %d\n",
+                        attr2->mode, attr1->mode);
+                ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if (attr1->nlink != attr2->nlink) {
+        if (attr1->nlink == (unsigned int)0xFFFFFFFF) {
+                prev_warn = TRUE;
+                if (ret) {
+                        verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                                fname, op);
+                }
+                verror(VAL_BATCH, I, "    nlink: current = %d, previous =  %d\n",
+                        attr2->nlink, attr1->nlink);
+                attr1->nlink =  attr2->nlink;
+                ret = FALSE;
+        }
+        else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    nlink: current = %d, previous =  %d\n",
+                        attr2->nlink, attr1->nlink);
+                ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+
+    /*
+     * Check for user "nobody", UID -2, which may be untranslated from
+     * sixteen-bit two's complement.
+     */
+    if (attr1->uid != attr2->uid && !((attr2->uid == (unsigned int)0xFFFFFFFE ||
+        attr2->uid == 65534) && attr1->uid ==0)) {
+        if (attr1->uid == (unsigned int)0xFFFFFFFF) {
+                prev_warn = TRUE;
+                if (ret) {
+                        verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                                fname, op);
+                }
+                verror(VAL_BATCH, I, "    uid: current = %d, previous =  %d\n",
+                        attr2->uid, attr1->uid);
+                attr1->uid =  attr2->uid;
+                ret = FALSE;
+        }
+        else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    uid: current = %d, previous =  %d\n",
+                        attr2->uid, attr1->uid);
+                ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if (attr1->gid != attr2->gid && attr2->gid != 0) {
+/*
+    if (attr1->gid != attr2->gid) {
+*/
+        if (attr1->gid == (unsigned int)0xFFFFFFFF) {
+                prev_warn = TRUE;
+                if (ret) {
+                        verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                                fname, op);
+                }
+                verror(VAL_BATCH, I, "    gid: current = %d, previous =  %d\n",
+                        attr2->gid, attr1->gid);
+                attr1->gid =  attr2->gid;
+                ret = FALSE;
+        }
+        else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    gid: current = %d, previous =  %d\n",
+                        attr2->gid, attr1->gid);
+                ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if (attr1->size != attr2->size) {
+        if (strcmp(op, Ops[WRITE].name)) {
+            if (attr1->size == (unsigned int)0xFFFFFFFF) {
+                prev_warn = TRUE;
+                if (ret) {
+                        verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                                fname, op);
+                }
+                verror(VAL_BATCH, I, "    size: current = %d, previous =  %d\n",
+                        attr2->size, attr1->size);
+                attr1->size =  attr2->size;
+                ret = FALSE;
+            }
+            else {
+                if (ret) {
+                        verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                            fname, op);
+                }
+                verror(VAL_BATCH, E, "    size: current = %d, previous =  %d\n",
+                        attr2->size, attr1->size);
+                ret = FALSE;
+                flag_error = TRUE;
+            }
+        }
+    }
+
+    if (attr1->blocksize != attr2->blocksize) {
+        if (attr1->blocksize == (unsigned int)0xFFFFFFFF) {
+             prev_warn = TRUE;
+             if (ret) {
+                     verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                             fname, op);
+             }
+             verror(VAL_BATCH, I, "    blocksize: current = %d, previous =  %d\n",
+                     attr2->blocksize, attr1->blocksize);
+             attr1->blocksize =  attr2->blocksize;
+             ret = FALSE;
+        }
+        else {
+             if (ret) {
+                     verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                         fname, op);
+             }
+             verror(VAL_BATCH, E, "    blocksize: current = %d, previous =  %d\n",
+                     attr2->blocksize, attr1->blocksize);
+             ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+
+    /* compare rdev only if type == NFCHR or NFBLK */
+    if ((attr1->type == NFCHR || attr1->type == NFBLK) &&
+        attr1->rdev != attr2->rdev) {
+        if (attr1->rdev == (unsigned int)0xFFFFFFFF) {
+             prev_warn = TRUE;
+             if (ret) {
+                     verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                             fname, op);
+             }
+             verror(VAL_BATCH, I, "    rdev: current = %d, previous =  %d\n",
+                     attr2->rdev, attr1->rdev);
+             attr1->rdev =  attr2->rdev;
+             ret = FALSE;
+        }
+        else {
+             if (ret) {
+                     verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                         fname, op);
+             }
+             verror(VAL_BATCH, E, "    rdev: current = %d, previous =  %d\n",
+                     attr2->rdev, attr1->rdev);
+             ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+
+    /*
+     * The NFS specification does not require that the number of blocks
+     * associated with a file remain constant.  Certain file systems
+     * may pre-allocate more blocks than necessary then trim them
+     * back ("garbage collect") or even blow holes in files that have
+     * all zero blocks.
+     * We must check that we never get back -1.
+     */
+    if (attr1->blocks != attr2->blocks) {
+        if (strcmp(op, Ops[WRITE].name)) {
+            if (attr1->blocks == (unsigned int)0xFFFFFFFF) {
+                 prev_warn = TRUE;
+                 if (ret) {
+                     verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                             fname, op);
+                 }
+                verror(VAL_BATCH, I, "    blocks: current = %d, previous =  %d\n",
+                         attr2->blocks, attr1->blocks);
+                 attr1->blocks =  attr2->blocks;
+                 ret = FALSE;
+            }
+        }
+    }
+
+
+    if (attr1->fsid != attr2->fsid) {
+        if (attr1->fsid == (unsigned int)0xFFFFFFFF) {
+             prev_warn = TRUE;
+             if (ret) {
+                     verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                             fname, op);
+             }
+             verror(VAL_BATCH, I, "    fsid: current = %d, previous =  %d\n",
+                     attr2->fsid, attr1->fsid);
+             attr1->fsid =  attr2->fsid;
+             ret = FALSE;
+        }
+        else {
+             if (ret) {
+                     verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                         fname, op);
+             }
+             verror(VAL_BATCH, E, "    fsid: current = %d, previous =  %d\n",
+                     attr2->fsid, attr1->fsid);
+             ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if (attr1->fileid != attr2->fileid) {
+        if (attr1->fileid == (unsigned int)0xFFFFFFFF) {
+             prev_warn = TRUE;
+             if (ret) {
+                     verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                             fname, op);
+             }
+             verror(VAL_BATCH, I, "    fileid: current = %d, previous =  %d\n",
+                     attr2->fileid, attr1->fileid);
+             attr1->fileid =  attr2->fileid;
+             ret = FALSE;
+        }
+        else {
+             if (ret) {
+                     verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                         fname, op);
+             }
+             verror(VAL_BATCH, E, "    fileid: current = %d, previous =  %d\n",
+                     attr2->fileid, attr1->fileid);
+             ret = FALSE;
+                flag_error = TRUE;
+        }
+    }
+
+    if (prev_warn) {
+        verror(VAL_BATCH, I,
+                "\n        Warning: the previous value of a field is -1,\n");
+        verror(VAL_BATCH, I,
+                "        this resulted from an unused field returned by\n");
+        verror(VAL_BATCH, I,
+                "        the previous operation on this file/directory.\n");
+        verror(VAL_BATCH, I,
+            "        The current value is now stored for future comparison\n\n");
+    }
+
+    if (flag_error)
+        verror(VAL_BATCH, W,"\n");
+
+    return(flag_error);
+
+} /* ckompare_fattr */
+
+
+static int
+compare_sattr(
+    char *      op,
+    char *      fname,
+    sattr *     attr1,
+    fattr *     attr2)
+{
+    int         ret = TRUE;
+    char        msg[80];
+
+    msg[0] = '\0';
+
+    if (attr1->mode != (unsigned int)0xFFFFFFFF &&
+        (attr1->mode & NFSMODE_MASK) != (attr2->mode & NFSMODE_MASK)) {
+        if (ret) {
+            verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                    fname, op);
+
+        }
+        verror(VAL_BATCH, E, "    mode: returned = %7o, specified = %7o\n",
+                attr2->mode, attr1->mode);
+        ret = FALSE;
+    }
+
+    /*
+     * Check for user "nobody", UID -2, which may be untranslated from
+     * sixteen-bit two's complement.
+     */
+    if (attr1->uid != (unsigned int)0xFFFFFFFF && attr1->uid != attr2->uid &&
+               !((attr2->uid == (unsigned int)0xFFFFFFFE ||
+               attr2->uid == 65534) &&
+                       attr1->uid == 0)) {
+        if (ret) {
+            verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                    fname, op);
+        }
+        if (attr1->uid == 0)
+            (void) strcat(msg," (is root UID mapped to other UID?)");
+        verror(VAL_BATCH, E, "    uid: returned = %d, specified = %d %s\n",
+                attr2->uid, attr1->uid, msg);
+        ret = FALSE;
+    }
+    if (attr1->gid != (unsigned int)0xFFFFFFFF &&
+                       attr1->gid != attr2->gid &&
+                       attr2->gid != 0) {
+/*
+   if (attr1->gid != 0xFFFFFFFF && attr1->gid != attr2->gid) {
+*/
+        if (ret) {
+            verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                    fname, op);
+        }
+        verror(VAL_BATCH, E, "    gid: returned = %d, specified = %d\n",
+                attr2->gid, attr1->gid);
+        ret = FALSE;
+    }
+
+    if (attr1->size != (unsigned int)0xFFFFFFFF &&
+                       attr1->size != attr2->size) {
+        if (ret) {
+            verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                    fname, op);
+        }
+        verror(VAL_BATCH, E, "    size: returned = %d, specified = %d\n",
+                attr2->size, attr1->size);
+        ret = FALSE;
+    }
+
+    if (!ret)
+        verror(VAL_BATCH, W,"\n");
+
+    return(ret);
+
+} /* compare_sattr */
+
+
+/*
+ * Return the BSD checksum of buf[0..len-1]
+ */
+static uint16_t
+sum(
+    unsigned char *     buf,
+    uint_t              len)
+{
+    uint16_t      cksum;
+
+    cksum = 0;
+    for (; len--; buf++) {
+        if (cksum & 1)
+            cksum = (cksum >> 1) + 0x8000;
+        else
+            cksum >>= 1;
+        cksum += (uint16_t) *buf;
+        cksum &= 0xFFFF;
+    }
+    return(cksum);
+} /* sum */
+
+
+static void
+validate_remove(void)
+{
+    diropargs   args;
+    nfsstat     reply;
+    diropres    lreply;
+    int         filenum;
+    char *      op;
+
+    (void) memmove((char *) &args.dir, (char *) &Export_dir.fh2, NFS_FHSIZE);
+
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+        if (Io_files[filenum].state != Exists)
+            continue;
+
+        args.name = Io_files[filenum].file_name;
+
+        if (Io_files[filenum].attributes2.type == NFDIR) {
+            op = Ops[RMDIR].name;
+            verror(VAL_VERBOSE, I, "validating rmdir %s ...\n",
+                    args.name);
+            val_op_rmdir(&args, &reply);
+        } else {
+            op = Ops[REMOVE].name;
+            verror(VAL_VERBOSE, I, "validating remove %s ...\n",
+                    args.name);
+            val_op_remove(&args, &reply);
+        }
+
+        if (reply == NFS_OK) {
+            /* make sure the file is removed from the directory */
+            val_op_lookup(&args, &lreply);
+
+            if (lreply.status == NFSERR_NOENT) {
+                Io_files[filenum].state = Nonexistent;
+            } else if (lreply.status == NFS_OK) {
+                verror(VAL_BATCH, W, "%s %s: file not removed\n",
+                       op, Io_files[filenum].file_name);
+            } else {
+                verror(VAL_BATCH, W, "lookup %s failed: %m\n",
+                       Io_files[filenum].file_name);
+
+            }
+        } else {
+            verror(VAL_BATCH, W, "%s %s failed: %m\n", op,
+                    Io_files[filenum].file_name);
+        }
+
+    }
+
+} /* validate_remove */
+
+
+static void
+validate_cleanup(void)
+{
+    free(Io_files);
+    free(Non_io_files);
+    free(Dirs);
+    free(Symlinks);
+    clnt_destroy(NFS_client);
+
+} /* validate_cleanup */
+
+
+static void
+validate_exit(void)
+{
+    if (!Validate_errors) {
+        verror(VAL_BATCH, I, "validation completed successfully.\n");
+        exit(0);
+    } else {
+        verror(VAL_BATCH, I, "validation terminated with errors\n");
+        exit(1);
+    }
+
+} /* validate_exit */
+
+
+/* PRINTFLIKE3 */
+static void
+verror(
+    int         opt,
+    ValMsgType  msgtype,
+    char *      fmt,
+    ...)
+{
+    va_list    ap;
+    char        buf[1024];
+    char *      bp = buf;
+    char *      fp;
+    int         repeat;
+    char *     sp;
+
+    va_start(ap, fmt);
+
+    /*
+     * Expand the "%m" format character into the descriptive string
+     * for the current value of errno.  Printf handles the other "%"
+     * formatting characters.
+     */
+    if (Validate >= opt) {
+        for (fp = fmt; *fp; fp++) {
+            if (*fp == '%' && fp[1] == 'm') {
+               if ((sp = strerror(errno)) == NULL) {
+                    (void) sprintf(bp, "unknown error %d", errno);
+                } else {
+                    (void) strcpy(bp, sp);
+                }
+                bp = buf + strlen(buf);
+                fp++;
+            } else {
+                *bp++ = *fp;
+            }
+        }
+        *bp = '\0';
+        (void) vprintf(buf, ap);
+    }
+    va_end(ap);
+
+    if (msgtype != I)
+        Validate_errors++;
+
+    if (msgtype == W && Validate == VAL_INTERACTIVE) {
+        repeat = 1;
+        while (repeat) {
+            char ans[80];
+
+            (void) fprintf(stderr, "continue? (y or n)  ");
+            if (!fgets(ans,80,stdin)) {
+                (void) fprintf(stderr, "\n");
+                continue;
+            }
+            if (ans[0] == 'n' || ans[0] == 'N') {
+                validate_exit();
+                exit(1);
+            } else if (ans[0] == 'y' || ans[0] == 'Y') {
+                repeat = 0;
+                break;
+            }
+        }
+    }
+
+} /* verror */
+
+
+static void
+val_op_null(void)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_NULL, 
+               xdr_void, (char *)0, xdr_void, (char *)0, 
+               Nfs_timers[Ops[NULLCALL].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "null");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_getattr(fhandle_t *args, attrstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_GETATTR, 
+           xdr_getattr, (char *)args, xdr_getattr, (char *)reply, 
+           Nfs_timers[Ops[GETATTR].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "getattr");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_setattr(sattrargs *args, attrstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_SETATTR, 
+               xdr_setattr, (char *)args, xdr_setattr, (char *)reply, 
+               Nfs_timers[Ops[SETATTR].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "setattr");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_lookup(diropargs *args, diropres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_LOOKUP, 
+               xdr_lookup, (char *)args, xdr_lookup, (char *)reply, 
+               Nfs_timers[Ops[LOOKUP].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "lookup");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_readlink(fhandle_t *args, readlinkres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_READLINK, 
+               xdr_readlink, (char *)args, xdr_readlink, (char *)reply, 
+               Nfs_timers[Ops[READLINK].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "readlink");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_read(readargs *args, readres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_READ, 
+               xdr_read, (char *)args, xdr_read, (char *)reply, 
+               Nfs_timers[Ops[READ].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "read");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_write(writeargs *args, attrstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client,
+               NFSPROC_WRITE, xdr_write, (char *)args, xdr_write, (char *)reply,
+               Nfs_timers[Ops[WRITE].call_class]);
+
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+                   clnt_perror(NFS_client, "write");
+                   Validate_errors++;
+                   validate_exit();
+            }
+       }
+}
+
+static void
+val_op_create(createargs *args, diropres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client,
+           NFSPROC_CREATE, xdr_create, (char *)args, xdr_create, (char *)reply, 
+           Nfs_timers[Ops[CREATE].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "create");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_remove(diropargs *args, nfsstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client,
+               NFSPROC_REMOVE, xdr_remove, (char *)args, xdr_remove, (char *)reply, 
+               Nfs_timers[Ops[REMOVE].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "remove");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_rename(renameargs *args, nfsstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_RENAME, 
+               xdr_rename, (char *)args, xdr_rename, (char *)reply, 
+               Nfs_timers[Ops[RENAME].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "rename");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_link(linkargs *args, nfsstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_LINK, 
+               xdr_link, (char *)args, xdr_link, (char *)reply, 
+               Nfs_timers[Ops[LINK].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "link");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_symlink(symlinkargs *args, nfsstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_SYMLINK, 
+               xdr_symlink, (char *)args, xdr_symlink, (char *)reply, 
+               Nfs_timers[Ops[SYMLINK].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "symlink");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_mkdir(mkdirargs *args, diropres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_MKDIR, 
+               xdr_mkdir, (char *)args, xdr_mkdir, (char *)reply, 
+               Nfs_timers[Ops[MKDIR].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "mkdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_rmdir(diropargs *args, nfsstat *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_RMDIR, 
+               xdr_rmdir, (char *)args, xdr_rmdir, (char *)reply, 
+               Nfs_timers[Ops[RMDIR].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "rmdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_readdir(readdirargs *args, readdirres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_READDIR, 
+               xdr_readdir, (char *)args, xdr_readdir, (char *)reply, 
+               Nfs_timers[Ops[READDIR].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "readdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_statfs(fhandle_t *args, statfsres *reply)
+{
+       int rpc_stat;
+
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC_STATFS, 
+               xdr_statfs, (char *)args, xdr_statfs, (char *)reply, 
+               Nfs_timers[Ops[FSSTAT].call_class]);
+            if (rpc_stat == RPC_SUCCESS)
+                break;
+            if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "statfs");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+static void
+create_tmp_handles(void)
+{
+       int filenum;
+       for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+               if(Io_files[filenum].fh_data == (sfs_fh_data *)0)
+               {
+                       Io_files[filenum].fh_data = 
+                                       calloc(1,sizeof(sfs_fh_data));
+                       Io_files[filenum].attributes2.type = NFNON;
+                       Io_files[filenum].attributes3.type = NF3NON;
+               }
+       }
+}
+
+static void
+delete_tmp_handles()
+{
+       int filenum;
+       for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+               if(Io_files[filenum].fh_data != (sfs_fh_data *)0)
+               {
+                       free(Io_files[filenum].fh_data);
+                       Io_files[filenum].fh_data=(sfs_fh_data *)0;
+               }
+       }
+}
+
+
+
+
+
+
+
+
diff --git a/TBBT/trace_play/sfs_2_xdr.c b/TBBT/trace_play/sfs_2_xdr.c
new file mode 100644 (file)
index 0000000..7c84899
--- /dev/null
@@ -0,0 +1,735 @@
+#ifndef lint
+static char sfs_c_xdrSid[] = "@(#)sfs_2_xdr.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * -------------------------- sfs_c_xdr.c --------------------------
+ *
+ *      XDR routines for the nfs protocol.
+ *
+ *.Exported_routines
+ *     bool_t xdr_fhstatus(XDR *, struct fhstatus *)
+ *     bool_t xdr_path(XDR *, char **)
+ *     bool_t xdr_fattr(XDR *, fattr *)
+ *     bool_t xdr_sattr(XDR *, sattr *)
+ *     bool_t xdr_null(void)
+ *     bool_t xdr_getattr(XDR *, char *)
+ *     bool_t xdr_setattr(XDR *, char *)
+ *     bool_t xdr_root(void)
+ *     bool_t xdr_lookup(XDR *, char *)
+ *     bool_t xdr_readlink(XDR *, char *)
+ *     bool_t xdr_read(XDR *, char *)
+ *     bool_t xdr_write(XDR *, char *)
+ *     bool_t xdr_create(XDR *, char *)
+ *     bool_t xdr_remove(XDR *, char *)
+ *     bool_t xdr_rename(XDR *, char *)
+ *     bool_t xdr_link(XDR *, char *)
+ *     bool_t xdr_symlink(XDR *, char *)
+ *     bool_t xdr_mkdir(XDR *, char *)
+ *     bool_t xdr_rmdir(XDR *, char *)
+ *     bool_t xdr_readdir(XDR *, char *)
+ *     bool_t xdr_statfs(XDR *, char *)
+ *
+ *.Local_routines
+ *     bool_t xdr_timeval(XDR *, nfstime *)
+ *     bool_t xdr_nfsstat(XDR *, nfsstat *)
+ *     bool_t xdr_ftype(XDR *, ftype *)
+ *     bool_t xdr_diropargs(XDR *, diropargs *)
+ *     bool_t xdr_diropres(XDR *, diropres *)
+ *     bool_t xdr_attrstat(XDR *, attrstat *)
+ *
+ *.Revision_History
+ *      28-NOv-91      Teelucksingh    ANSI C
+ *     25-Jun-91       Santa Wiryaman  Changed return values to TRUE when
+ *                                     status != NFS_OK.  This way we can
+ *                                     decode NFS error messages.
+ *     17-May-90       Richard Bean    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+
+/*
+ * -----------------------  Forward Definitions  -----------------------
+ */
+
+static bool_t xdr_f_handle(XDR *, fhandle_t *);
+static bool_t xdr_fattr(XDR *, fattr *);
+static bool_t xdr_sattr(XDR *, sattr *);
+static bool_t xdr_timeval(XDR *, nfstime *);
+static bool_t xdr_nfsstat(XDR *, nfsstat *);
+static bool_t xdr_ftype(XDR *, ftype *);
+static bool_t xdr_diropargs(XDR *, diropargs *);
+static bool_t xdr_diropres(XDR *, diropres *);
+static bool_t xdr_attrstat(XDR *, attrstat *);
+
+/*
+ * -----------------------  SFS XDR Routines  -------------------------
+ */
+
+
+static bool_t
+xdr_f_handle(
+    XDR *              xdrs,
+    fhandle_t *                fhandle_ptr)
+{
+    return(xdr_opaque(xdrs, (char *)fhandle_ptr, NFS_FHSIZE));
+}
+
+
+static bool_t
+xdr_timeval(
+    XDR *              xdrs,
+    nfstime *          timeval_ptr)
+{
+    return(xdr_int32_t(xdrs, (int32_t *) &timeval_ptr->seconds) &&
+          xdr_int32_t(xdrs, (int32_t *) &timeval_ptr->useconds));
+}
+
+
+static bool_t
+xdr_nfsstat(
+    XDR *              xdrs,
+    nfsstat *          nfsstat_ptr)
+{
+    return(xdr_enum(xdrs, (enum_t *) nfsstat_ptr));
+}
+
+
+static bool_t
+xdr_ftype(
+    XDR *              xdrs,
+    ftype *            ftype_ptr)
+{
+    return(xdr_enum(xdrs, (enum_t *) ftype_ptr));
+}
+
+
+bool_t
+xdr_fhstatus(
+    XDR *              xdrs,
+    struct fhstatus *  fhsp)
+{
+    if (!xdr_nfsstat(xdrs, (nfsstat *) &fhsp->fhs_status)) {
+       return(FALSE);
+    }
+    if (fhsp->fhs_status != (int)NFS_OK) {
+       return(TRUE);
+    }
+    return(xdr_f_handle(xdrs, &fhsp->fhs_fh));
+}
+
+
+bool_t
+xdr_path(
+    XDR *              xdrs,
+    char **            pathp)
+{
+    return(xdr_string(xdrs, pathp, NFS_MAXPATHLEN));
+}
+
+
+static bool_t
+xdr_fattr(
+    XDR *              xdrs,
+    fattr *            fattr_ptr)
+{
+    return(xdr_ftype(xdrs, &fattr_ptr->type) &&
+          xdr_u_int(xdrs, &fattr_ptr->mode) &&
+          xdr_u_int(xdrs, &fattr_ptr->nlink) &&
+          xdr_u_int(xdrs, &fattr_ptr->uid) &&
+          xdr_u_int(xdrs, &fattr_ptr->gid) &&
+          xdr_u_int(xdrs, &fattr_ptr->size) &&
+          xdr_u_int(xdrs, &fattr_ptr->blocksize) &&
+          xdr_u_int(xdrs, &fattr_ptr->rdev) &&
+          xdr_u_int(xdrs, &fattr_ptr->blocks) &&
+          xdr_u_int(xdrs, &fattr_ptr->fsid) &&
+          xdr_u_int(xdrs, &fattr_ptr->fileid) &&
+          xdr_timeval(xdrs, &fattr_ptr->atime) &&
+          xdr_timeval(xdrs, &fattr_ptr->mtime) &&
+          xdr_timeval(xdrs, &fattr_ptr->ctime));
+}
+
+
+static bool_t
+xdr_sattr(
+    XDR *              xdrs,
+    sattr *            sattr_ptr)
+{
+    return(xdr_u_int(xdrs, &sattr_ptr->mode) &&
+          xdr_u_int(xdrs, &sattr_ptr->uid) &&
+          xdr_u_int(xdrs, &sattr_ptr->gid) &&
+          xdr_u_int(xdrs, &sattr_ptr->size) &&
+          xdr_timeval(xdrs, &sattr_ptr->atime) &&
+          xdr_timeval(xdrs, &sattr_ptr->mtime));
+}
+
+
+static bool_t
+xdr_diropargs(
+    XDR *              xdrs,
+    diropargs *                dir_args_ptr)
+{
+    return(xdr_f_handle(xdrs, &dir_args_ptr->dir) &&
+          xdr_path(xdrs, &dir_args_ptr->name));
+}
+
+
+static bool_t
+xdr_diropres(
+    XDR *              xdrs,
+    diropres *         dir_res_ptr)
+{
+    if (!xdr_nfsstat(xdrs, &dir_res_ptr->status)) {
+       return(FALSE);
+    }
+
+    if (dir_res_ptr->status == NFS_OK) {
+       return(xdr_f_handle(xdrs, &dir_res_ptr->diropres_u.diropres.file) &&
+              xdr_fattr(xdrs, &dir_res_ptr->diropres_u.diropres.attributes));
+    }
+    return(TRUE);
+}
+
+
+static bool_t
+xdr_attrstat(
+    XDR *              xdrs,
+    attrstat *         attrstat_ptr)
+{
+    if (!xdr_nfsstat(xdrs, &attrstat_ptr->status)) {
+       return(FALSE);
+    }
+
+    if (attrstat_ptr->status == NFS_OK) {
+       return(xdr_fattr(xdrs, &attrstat_ptr->attrstat_u.attributes));
+    }
+    return(TRUE);
+}
+
+
+bool_t
+xdr_getattr(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    fhandle_t *                fhandle_ptr;
+    attrstat *         attrstat_ptr;
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           fhandle_ptr = (fhandle_t *) params_ptr;
+           return(xdr_f_handle(xdrs, fhandle_ptr));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           attrstat_ptr = (attrstat *) params_ptr;
+           return(xdr_attrstat(xdrs, attrstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_setattr(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    sattrargs *                sattrargs_ptr;
+    attrstat *         attrstat_ptr;
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           sattrargs_ptr = (sattrargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &sattrargs_ptr->file) &&
+                  xdr_sattr(xdrs, &sattrargs_ptr->attributes));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           attrstat_ptr = (attrstat *) params_ptr;
+           return(xdr_attrstat(xdrs, attrstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_lookup(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    diropargs *                diropargs_ptr;
+    diropres *         diropres_ptr;
+
+
+    switch(xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           diropargs_ptr = (diropargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &diropargs_ptr->dir) &&
+                  xdr_path(xdrs, &diropargs_ptr->name));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           diropres_ptr = (diropres *) params_ptr;
+           return(xdr_diropres(xdrs, diropres_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+bool_t
+xdr_readlink(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    fhandle_t *                fhandle_ptr;
+    readlinkres *      readlinkres_ptr;
+
+    switch(xdrs->x_op) {
+       case XDR_ENCODE:
+           fhandle_ptr = (fhandle_t *) params_ptr;
+           return(xdr_f_handle(xdrs, fhandle_ptr));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           readlinkres_ptr = (readlinkres *) params_ptr;
+           if (!xdr_nfsstat(xdrs, &readlinkres_ptr->status)) {
+               return(FALSE);
+           }
+           if (readlinkres_ptr->status != NFS_OK) {
+               return(TRUE);
+           }
+           return(xdr_bytes(xdrs, &readlinkres_ptr->readlinkres_u.data,
+                            (unsigned int *)
+                            &readlinkres_ptr->readlinkres_u.len,
+                            (unsigned int) NFS_MAXPATHLEN));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_read(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    readargs *         readargs_ptr;
+    readres *          readres_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           readargs_ptr = (readargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &readargs_ptr->file) &&
+                  xdr_u_int(xdrs, &readargs_ptr->offset) &&
+                  xdr_u_int(xdrs, &readargs_ptr->count) &&
+                  xdr_u_int(xdrs, &readargs_ptr->totalcount));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           readres_ptr = (readres *) params_ptr;
+           if (!xdr_nfsstat(xdrs, &readres_ptr->status)) {
+               return(FALSE);
+           }
+           if (readres_ptr->status != NFS_OK) {
+               return(TRUE);
+           }
+           return(xdr_fattr(xdrs, &readres_ptr->readres_u.reply.attributes) &&
+                  xdr_bytes(xdrs, &readres_ptr->readres_u.reply.data.data_val,
+                            &readres_ptr->readres_u.reply.data.data_len,
+                            (unsigned int) NFS_MAXDATA));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+bool_t
+xdr_write(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    writeargs *                writeargs_ptr;
+    attrstat *         attrstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           writeargs_ptr = (writeargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &writeargs_ptr->file) &&
+                  xdr_u_int(xdrs, &writeargs_ptr->beginoffset) &&
+                  xdr_u_int(xdrs, &writeargs_ptr->offset) &&
+                  xdr_u_int(xdrs, &writeargs_ptr->totalcount) &&
+                  xdr_bytes(xdrs, &writeargs_ptr->data.data_val,
+                                  &writeargs_ptr->data.data_len,
+                                  (unsigned int) NFS_MAXDATA));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           attrstat_ptr = (attrstat *) params_ptr;
+           return(xdr_attrstat(xdrs, attrstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_create(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    createargs *       createargs_ptr;
+    diropres *         diropres_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           createargs_ptr = (createargs *) params_ptr;
+           return(xdr_diropargs(xdrs, &createargs_ptr->where) &&
+                  xdr_sattr(xdrs, &createargs_ptr->attributes));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           diropres_ptr = (diropres *) params_ptr;
+           return(xdr_diropres(xdrs, diropres_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_remove(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    diropargs *                diropargs_ptr;
+    nfsstat *          nfsstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           diropargs_ptr = (diropargs *) params_ptr;
+           return(xdr_diropargs (xdrs, diropargs_ptr));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           nfsstat_ptr = (nfsstat *) params_ptr;
+           return(xdr_nfsstat(xdrs, nfsstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_rename(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    renameargs *       renameargs_ptr;
+    nfsstat *          nfsstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           renameargs_ptr = (renameargs *) params_ptr;
+           return(xdr_diropargs(xdrs, &renameargs_ptr->from) &&
+                  xdr_diropargs(xdrs, &renameargs_ptr->to));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           nfsstat_ptr = (nfsstat *) params_ptr;
+           return(xdr_nfsstat(xdrs, nfsstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_link(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    linkargs *         linkargs_ptr;
+    nfsstat *          nfsstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           linkargs_ptr = (linkargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &linkargs_ptr->from) &&
+                  xdr_diropargs(xdrs, &linkargs_ptr->to));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           nfsstat_ptr = (nfsstat *) params_ptr;
+           return(xdr_nfsstat(xdrs, nfsstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_symlink(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    symlinkargs *      symlinkargs_ptr;
+    nfsstat *          nfsstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           symlinkargs_ptr = (symlinkargs *) params_ptr;
+           return(xdr_diropargs(xdrs, &symlinkargs_ptr->from) &&
+                  xdr_path(xdrs, &symlinkargs_ptr->to) &&
+                  xdr_sattr(xdrs, &symlinkargs_ptr->attributes));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           nfsstat_ptr = (nfsstat *) params_ptr;
+           return(xdr_nfsstat(xdrs, nfsstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_mkdir(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    mkdirargs *                mkdirargs_ptr;
+    diropres *         diropres_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           mkdirargs_ptr = (mkdirargs *) params_ptr;
+           return(xdr_diropargs(xdrs, &mkdirargs_ptr->where) &&
+                  xdr_sattr(xdrs, &mkdirargs_ptr->attributes));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           diropres_ptr = (diropres *) params_ptr;
+           return(xdr_diropres(xdrs, diropres_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_rmdir(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    diropargs *                diropargs_ptr;
+    nfsstat *          nfsstat_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           diropargs_ptr = (diropargs *) params_ptr;
+           return(xdr_diropargs(xdrs, diropargs_ptr));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           nfsstat_ptr = (nfsstat *) params_ptr;
+           return(xdr_nfsstat(xdrs, nfsstat_ptr));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+bool_t
+xdr_readdir(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    readdirargs *      readdirargs_ptr;
+    readdirres *       readdirres_ptr;
+    entry *            entry_ptr;
+    int                        n;              /* entry ctr */
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           /* LINTED pointer cast */
+           readdirargs_ptr = (readdirargs *) params_ptr;
+           return(xdr_f_handle(xdrs, &readdirargs_ptr->dir) &&
+                  xdr_opaque(xdrs, (char *) readdirargs_ptr->cookie,
+                                   NFS_COOKIESIZE) &&
+                  xdr_u_int(xdrs, &readdirargs_ptr->count));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           readdirres_ptr = (readdirres *) params_ptr;
+           if (!xdr_nfsstat(xdrs, &readdirres_ptr->status)) {
+               return(FALSE);
+           }
+           if (readdirres_ptr->status != NFS_OK) {
+               return(TRUE);
+           }
+
+           /*
+            * go thru the stream of entries until hit an invalid one
+            * or have gotten all the user asked for.
+            *
+            * max_entries is read to obtain a maximum.  it is written
+            * to return how many entries were decoded.
+            */
+           entry_ptr = readdirres_ptr->readdirres_u.reply.entries;
+
+           n = 0;
+           while (n < readdirres_ptr->readdirres_u.reply.max_entries) {
+               if (!xdr_bool(xdrs, &entry_ptr->valid)) {
+                   return(FALSE);
+               }
+
+               if (!entry_ptr->valid) {
+                   break;
+               }
+
+               if (!xdr_u_int(xdrs, &entry_ptr->fileid)) {
+                   return(FALSE);
+               }
+
+               if (!xdr_uint16_t(xdrs, &entry_ptr->name_len)) {
+                   return(FALSE);
+               }
+
+               if (!xdr_opaque(xdrs, entry_ptr->name, entry_ptr->name_len)) {
+                   return(FALSE);
+               }
+
+               if (!xdr_opaque(xdrs, entry_ptr->cookie, NFS_COOKIESIZE)) {
+                   return(FALSE);
+               }
+
+               n++;
+               entry_ptr++;
+           } /* while extracting entries */
+
+           /* If we are at the user's data buffer limit, stop right now.  */
+           if (n == readdirres_ptr->readdirres_u.reply.max_entries) {
+               return(TRUE);
+           }
+
+           /* Return how many entries were gotten for the dirlist */
+           readdirres_ptr->readdirres_u.reply.max_entries = n;
+
+           /* check the EOF flag for the dirlist */
+           if(!xdr_bool(xdrs, &readdirres_ptr->readdirres_u.reply.eof)) {
+               return(FALSE);
+           }
+
+           return(TRUE);
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+bool_t
+xdr_statfs(
+    XDR *              xdrs,
+    char *             params_ptr)
+{
+    fhandle_t *                fhandle_ptr;
+    statfsres *                statfsres_ptr;
+
+
+    switch (xdrs->x_op) {
+       case XDR_ENCODE:
+           fhandle_ptr = (fhandle_t *) params_ptr;
+           return(xdr_f_handle(xdrs, fhandle_ptr));
+
+       case XDR_DECODE:
+           /* LINTED pointer cast */
+           statfsres_ptr = (statfsres *) params_ptr;
+           if (!xdr_nfsstat(xdrs, &statfsres_ptr->status)) {
+               return(FALSE);
+           }
+           if (statfsres_ptr->status != NFS_OK) {
+               return(TRUE);
+           }
+           return(xdr_u_int(xdrs, &statfsres_ptr->statfsres_u.reply.tsize) &&
+                  xdr_u_int(xdrs, &statfsres_ptr->statfsres_u.reply.bsize) &&
+                  xdr_u_int(xdrs, &statfsres_ptr->statfsres_u.reply.blocks) &&
+                  xdr_u_int(xdrs, &statfsres_ptr->statfsres_u.reply.bfree) &&
+                  xdr_u_int(xdrs, &statfsres_ptr->statfsres_u.reply.bavail));
+
+       default:
+           return(FALSE);
+    } /* switch on operation */
+}
+
+
+/* sfs_c_xdr.c */
diff --git a/TBBT/trace_play/sfs_3_ops.c b/TBBT/trace_play/sfs_3_ops.c
new file mode 100644 (file)
index 0000000..19aef00
--- /dev/null
@@ -0,0 +1,2746 @@
+#ifndef lint
+static char sfs_3_opsSid[] = "@(#)sfs_3_ops.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_3_ops.c ---------------------
+ *
+ *      RPC routines to implement the NFS protocol.
+ *
+ *.Local Routines
+ *     int op_null(void)
+ *     int op_getattr(void)
+ *     int op_setattr(int)
+ *     int op_lookup(void)
+ *     int op_access(void)
+ *     int op_readlink(void)
+ *     int op_read(int)
+ *     int op_write(int, int, stable_how)
+ *     int op_create(void)
+ *     int op_mkdir(void);
+ *     int op_symlink(void);
+ *     int op_mknod(void);
+ *     int op_remove(void);
+ *     int op_rmdir(void);
+ *     int op_rename(void);
+ *     int op_link(void);
+ *     int op_readdir(void);
+ *     int op_readdirplus(void);
+ *     int op_fsstat(void);
+ *     int op_fsinfo(void);
+ *     int op_pathconf(void);
+ *     int op_commit(void);
+ *
+ *.Revision_History
+ *     30-Jun-94       ChakChung Ng    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+/*
+ * --------------------  Local NFS ops function --------------------
+ */
+static int op_null(void);
+static int op_getattr(void);
+static int op_setattr(int);
+static int op_lookup(void);
+static int op_access(void);
+static int op_readlink(void);
+static int op_read(int);
+static int op_write(int, int, stable_how);
+static int op_create(void);
+static int op_mkdir(void);
+static int op_symlink(void);
+static int op_mknod(void);
+static int op_remove(void);
+static int op_rmdir(void);
+static int op_rename(void);
+static int op_link(void);
+static int op_readdir(void);
+static int op_readdirplus(void);
+static int op_fsstat(void);
+static int op_fsinfo(void);
+static int op_pathconf(void);
+static int op_commit(void);
+static int op_nosys(void);
+static char *nfs3_strerror(int);
+
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+static sfs_op_type nfsv3_Ops[] = {
+
+/* name        mix   function         op    call  no  req  req  req  results */
+/*             pcnt                  class  targ call pcnt cnt  targ         */
+
+ { "null",        0, op_null,        Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    11, op_getattr,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, op_setattr,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     27, op_lookup,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, op_readlink,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       18, op_read,        Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       9, op_write,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, op_create,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, op_remove,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, op_rename,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, op_link,        Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, op_symlink,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, op_mkdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, op_rmdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     2, op_readdir,     Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, op_fsstat,             Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",      7, op_access,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",      5, op_commit,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",      1, op_fsinfo,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",       0, op_mknod,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",    0, op_pathconf,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 9, op_readdirplus, Read,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, 0,              Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+
+sfs_op_type *Ops;
+
+/*
+ * --------------------  RPC routines for NFS protocol --------------------
+ */
+
+void
+init_ops(void)
+{
+    Ops = nfsv3_Ops;
+    nfs_version = NFS_V3;
+}
+
+/*
+ * The routines below attempt to do over-the-wire operations.
+ * Each op tries to cause one or more of a particular
+ * NFS operation to go over the wire.  OPs return the success
+ * of their NFS call(s).  Each OP records how many calls it
+ * actually made in global data.
+ *
+ * An array of file information is kept for files existing in
+ * the test directory.  File handles, attributes, names, etc
+ * are stored in this array.
+ *
+ */
+
+/*
+ * Generic catch all for operations not covered by this protocol.
+ */
+static int
+op_nosys(int i)
+{
+       RFS_ASSERT (dep_tab[i].flag == TO_BE_SENT);
+       dep_tab[i].flag = DONE;
+    Ops[TOTAL].results.bad_calls++;
+       if (i==min_index)
+               adjust_min_index ();
+    return(0);
+}
+
+static struct biod_req *
+get_biod_reqp (int dep_tab_index)
+{
+       static int index = 0;
+       int i;
+
+       for (i=0; i<max_biod_reqs; i++, index = (index+1)%max_biod_reqs) {
+               if (biod_reqp[index].in_use == FALSE) {
+                       biod_reqp[index].in_use = TRUE;
+                       dep_tab[dep_tab_index].biod_index = index;
+                       biod_req[index].dep_tab_index = dep_tab_index;
+                       return (biod_reqp+index);
+               }
+       }
+}
+
+static int
+op_null(int i)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                ret;            /* ret val == call success */
+
+       struct biod_req * reqp;
+       struct ladtime call_timeout;
+
+       if (dep_tab[i].flag == SENT)
+               goto RECEIVE_REPLY;
+
+    op_ptr = &Ops[NULLCALL];
+       reqp = get_biod_reqp(i);
+
+       call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+
+    ret = 0;
+
+    /* make the call */
+    sfs_gettime(&reqp->start);
+       reqp->xid = boid_clnt_call(NFS_client, NFS3PROC_NULL, xdr_void, (char *)0);
+       if (reqp->xid != 0) {
+               reqp->timeout = reqp->start;
+               ADDTIME (reqp->timeout, call_timeout);
+               num_out_reqs++;
+               dep_tab[i].flag = SENT;
+       } else 
+               RFS_ASSERT (0);
+
+       return 0;
+
+RECEIVE_REPLY:
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_NULL,
+                       xdr_void, (char *)0, xdr_void, (char *)0,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: null_op call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_null */
+
+
+static int
+op_getattr(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    GETATTR3args       args;           /* fh to do op on */
+    GETATTR3res                reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[GETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+                                                       sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_GETATTR,
+                       xdr_GETATTR3args, (char *) &args,
+                       xdr_GETATTR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: getattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: getattr call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_getattr */
+
+
+/*
+ * perform an RPC setattr operation.  If 'truncate_size' is non-negative,
+ * truncate the file to that size.
+ */
+static int
+op_setattr(
+    int                truncate_size)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    SETATTR3args       args;
+    SETATTR3res                reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[SETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+                                                       sizeof (nfs_fh3));
+    args.new_attributes.mode.set_it = TRUE;
+    args.new_attributes.mode.mode = (uint32_t) 0666;
+    args.new_attributes.uid.set_it = FALSE;
+    args.new_attributes.uid.uid = (uint32_t) -1;
+    args.new_attributes.gid.set_it = FALSE;
+    args.new_attributes.gid.gid = (uint32_t) -1;
+    args.new_attributes.size.set_it = FALSE;
+    args.new_attributes.size.size._p._u = (uint32_t) ~0;
+    args.new_attributes.size.size._p._l = (uint32_t) -1;
+    args.new_attributes.atime.set_it = TRUE;
+    args.new_attributes.atime.atime.seconds = Cur_time.esec;
+    args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+    args.new_attributes.mtime.set_it = TRUE;
+    args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+    args.guard.check = FALSE;
+
+    /* handle file truncations */
+    if (truncate_size >= 0) {
+       args.new_attributes.size.set_it = TRUE;
+       args.new_attributes.size.size._p._u = (uint32_t) 0;
+       if (truncate_size > Cur_file_ptr->attributes3.size._p._l)
+           args.new_attributes.size.size._p._l = (uint32_t) 0;
+       else
+           args.new_attributes.size.size._p._l =
+               (uint32_t) Cur_file_ptr->attributes3.size._p._l -
+                                                               truncate_size;
+    }
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
+                       xdr_SETATTR3args, (char *) &args,
+                       xdr_SETATTR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_wcc.after.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: setattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: setattr call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_setattr */
+
+
+static int
+op_lookup(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[LOOKUP];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.what.dir, (char *) &Cur_file_ptr->dir->fh3,
+                                                       sizeof (nfs_fh3));
+    args.what.name = Cur_filename;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.object,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           /* We do lookup Nonexistent and this is not an error */
+           if (reply.status != NFS3ERR_NOENT ||
+                       Cur_file_ptr->state != Nonexistent) {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                       "%s: lookup call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+               }
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: lookup call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_lookup */
+
+
+static int
+op_access(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    ACCESS3args                args;
+    ACCESS3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[ACCESS];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->dir->fh3,
+                               sizeof (nfs_fh3));
+    args.access = ACCESS3_MODIFY;
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_ACCESS,
+                       xdr_ACCESS3args, (char *) &args,
+                       xdr_ACCESS3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: access call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: access call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_access */
+
+
+static int
+op_readlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READLINK3args      args;                   /* the args */
+    READLINK3res       reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[READLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    /*
+     * Note: this symlink may be bogus because SYMLINK does
+     * not return a symlink ... only a status.  So unless we have
+     * done a LOOKUP on this guy, the symlink will probably be bad.
+     * If it is bad it shows up as a symlink error in the results.
+     */
+    (void) memmove((char *) &args.symlink,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /* Have lower layers fill in the data directly. */
+    reply.resok.data = sym_data;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READLINK,
+                       xdr_READLINK3args, (char *) &args,
+                       xdr_READLINK3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           if (DEBUG_CHILD_RPC) {
+               (void) fprintf(stderr, "%s: READLINK on %s returned %s\n",
+                                   sfs_Myname, Cur_filename, sym_data);
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: readlink call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readlink */
+
+
+/*
+ * perform an RPC read operation of length 'xfer_size'
+ */
+static int
+op_read(
+    int                        xfer_size)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int                                cur_cnt;
+    int                                max_cnt;        /* packet ctrs */
+    char                       buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
+    READ3args                  args;
+    READ3res                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                size;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[READ];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /*
+     * Don't allow a read of less than one block size
+     */
+    if (xfer_size < Bytes_per_block)
+       xfer_size = Bytes_per_block;
+
+    /*
+     * randomly choose an offset that is a multiple of the block size
+     * and constrained by making the transfer fit within the file
+     */
+    args.offset._p._u = 0;
+    if (Cur_file_ptr->attributes3.size._p._l > xfer_size)
+       args.offset._p._l = Bytes_per_block * (sfs_random() %
+                       (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
+                       / Bytes_per_block) + 1));
+    else
+       args.offset._p._l = 0;
+
+    /* Have lower layers fill in the data directly.  */
+    reply.resok.data.data_len = 0;
+    reply.resok.data.data_val = buf;
+
+    /* first read the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block -1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       args.count = size;
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "read: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_READ,
+                               xdr_READ3args, (char *) &args,
+                               xdr_READ3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = (rpc_stat == RPC_SUCCESS && reply.status == NFS3_OK)
+                           ? reply.resok.data.data_len : 0;
+           Dump_offset = args.offset._p._l;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS3_OK) {
+                   Cur_file_ptr->state = Exists;
+                   (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.file_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   size = reply.resok.data.data_len;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: READ %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+                   args.offset._p._l += size;
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: read call NFS error %s on file %d\n",
+                                       sfs_Myname,
+                                       nfs3_strerror(reply.status),
+                                       Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                               "%s: read call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for reading max_cnt packets */
+    } /* for buffers and fragments */
+    return(ret);
+
+} /* op_read */
+
+char *
+init_write_buffer(
+    void)
+{
+    uint32_t *bp;
+    static uint32_t write_buf[DEFAULT_MAX_BUFSIZE / sizeof(uint32_t)];
+    uint32_t *be  = write_buf + (sizeof(write_buf) /
+                                                       sizeof(uint32_t));
+
+    if (write_buf[0] != (uint32_t)0xdeadbeef) {
+        for (bp = write_buf; bp < be; bp++)
+            *bp = (uint32_t)0xdeadbeef;
+    }
+    return (char *)write_buf;
+}
+
+
+/*
+ * Perform and RPC write operation of length 'xfer_size'.  If 'append_flag'
+ * is true, then write the data to the end of the file.
+ *
+ * If the stab_flag is set to UNSTABLE we issue the requests and then
+ * issue a op_commit to sync the data.
+ */
+static int
+op_write(
+    int                        xfer_size,
+    int                        append_flag,
+    stable_how         stab_flag)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    static char                        *buf = NULL;    /* the data buffer */
+    unsigned int               size;           /* size of data write */
+    int                                cur_cnt;        /* controls # NFS calls */
+    int                                max_cnt;
+    WRITE3args                 args;
+    WRITE3res                  reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    /*
+     * For now we treat DATA_SYNC to be the same as FILE_SYNC.
+     */
+    if (stab_flag == DATA_SYNC)
+       stab_flag = FILE_SYNC;
+
+    /*
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+
+    op_ptr = &Ops[WRITE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = 0;
+    if (append_flag == 1) {
+       args.offset._p._l = Cur_file_ptr->attributes3.size._p._l;
+    } else {
+       /*
+        * randomly choose an offset that is a multiple of the block size
+        * and constrained by making the transfer fit within the file
+        */
+       if (Cur_file_ptr->attributes3.size._p._l > xfer_size) {
+           args.offset._p._l = Bytes_per_block * (sfs_random() %
+                           (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
+                           / Bytes_per_block) + 1));
+       } else
+           args.offset._p._l = 0;
+    }
+
+    /* stab_flag has to be set in op() in sfs_3_chd.c */
+    args.stable = stab_flag;
+
+    /* first write the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block - 1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       args.count = size;
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "write: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           if (DEBUG_CHILD_RPC) {
+(void) fprintf(stderr, "%s: WRITE %s offset %u count %lu stable %d\n",
+sfs_Myname, Cur_filename, args.offset._p._l, args.count, args.stable);
+               (void) fflush(stderr);
+           }
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
+                               xdr_WRITE3args, (char *) &args,
+                               xdr_WRITE3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = args.data.data_len;
+           Dump_offset = args.offset._p._l;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS3_OK) {
+                   Cur_file_ptr->state = Exists;
+                   (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.file_wcc.after.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   args.offset._p._l += size;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: WRITE %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: write call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                               "%s: write call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for writing max_cnt packets */
+    } /* for buffers and fragments */
+
+    /*
+     * If we have not gotten an error and we were asked for an async write
+     * send a commit operation.
+     */
+    if (ret && stab_flag != FILE_SYNC)
+       ret += op_commit();
+
+    return(ret);
+
+} /* op_write */
+
+
+static int
+op_create(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    CREATE3args                args;
+    CREATE3res         reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[CREATE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.how.mode = UNCHECKED;
+    args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
+    args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+    args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+    args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.atime.atime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.size.size._p._u = (uint32_t) 0;
+    args.how.createhow3_u.obj_attributes.size.size._p._l = (uint32_t) 0;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
+                       xdr_CREATE3args, (char *) &args,
+                       xdr_CREATE3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: create call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: create call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_create */
+
+
+static int
+op_mkdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    MKDIR3args         args;
+    MKDIR3res          reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[MKDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.attributes.mode.set_it = TRUE;
+    args.attributes.mode.mode = (NFSMODE_DIR | 0777);
+    args.attributes.uid.set_it = TRUE;
+    args.attributes.uid.uid = Cur_uid;
+    args.attributes.gid.set_it = TRUE;
+    args.attributes.gid.gid = Cur_gid;
+    args.attributes.size.set_it = TRUE;
+    args.attributes.size.size._p._u = 0;
+    args.attributes.size.size._p._l = 512;
+    args.attributes.atime.set_it = TRUE;
+    args.attributes.atime.atime.seconds = Cur_time.esec;
+    args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+    args.attributes.mtime.set_it = TRUE;
+    args.attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
+                       xdr_MKDIR3args, (char *) &args,
+                       xdr_MKDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+            Cur_file_ptr->state = Empty_dir;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: mkdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: mkdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_mkdir */
+
+
+static int
+op_symlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target file */
+    SYMLINK3args       args;
+    SYMLINK3res                reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[SYMLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(SYMLINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+
+    (void) strcpy(sym_data, "./");
+    (void) strcat(sym_data, target_fileinfo_ptr->file_name);
+    args.symlink.symlink_attributes.size.set_it = TRUE;
+    args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
+    args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
+    args.symlink.symlink_data = sym_data;
+
+    args.symlink.symlink_attributes.mode.set_it = TRUE;
+    args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
+    args.symlink.symlink_attributes.uid.set_it = TRUE;
+    args.symlink.symlink_attributes.uid.uid = Cur_uid;
+    args.symlink.symlink_attributes.gid.set_it = TRUE;
+    args.symlink.symlink_attributes.gid.gid = Cur_gid;
+    args.symlink.symlink_attributes.atime.set_it = TRUE;
+    args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
+    args.symlink.symlink_attributes.atime.atime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.symlink.symlink_attributes.mtime.set_it = TRUE;
+    args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.symlink.symlink_attributes.mtime.mtime.nseconds =
+                                               Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
+                       xdr_SYMLINK3args, (char *) &args,
+                       xdr_SYMLINK3res, (char *) &reply,
+                       ((int)Current_test_phase < (int)Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           /*
+            * SYMLINK doesn't return a fh. If we try to access this symlink
+            * (eg, remove(), readlink()) before we do a lookup, we won't have
+            * a fh to use. So, we do a lookup call here. If it fails, we fill
+            * in what we can.
+            */
+           Cur_file_ptr->state = Exists;
+           if (op_lookup() == 0) {
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               Cur_file_ptr->attributes3.type = NF3LNK;
+               Cur_file_ptr->attributes3.mode = (NFSMODE_LNK|0777);
+               Cur_file_ptr->attributes3.uid = Cur_uid;
+               Cur_file_ptr->attributes3.gid = Cur_gid;
+               Cur_file_ptr->attributes3.atime.seconds = Cur_time.esec;
+               Cur_file_ptr->attributes3.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+               Cur_file_ptr->attributes3.mtime =
+                       Cur_file_ptr->attributes3.atime;
+           } else
+               ret++;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: symlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: symlink call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_symlink */
+
+
+static int
+op_mknod(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    MKNOD3args         args;
+    MKNOD3res          reply;
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[MKNOD];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.what.type = NF3FIFO;
+    args.what.mknoddata3_u.pipe_attributes.mode.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mode.mode = (NFSMODE_FIFO | 0777);
+    args.what.mknoddata3_u.pipe_attributes.uid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.uid.uid = Cur_uid;
+    args.what.mknoddata3_u.pipe_attributes.gid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.gid.gid = Cur_gid;
+    args.what.mknoddata3_u.pipe_attributes.size.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._u = (uint32_t) 0;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._l =
+                                                       (uint32_t) 512;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.seconds =
+                                                               Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_MKNOD,
+                       xdr_MKNOD3args, (char *) &args,
+                       xdr_MKNOD3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: mknod call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: mknod call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_mknod */
+
+
+static int
+op_remove(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    REMOVE3args                args;
+    REMOVE3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[REMOVE];
+    ret = 0;
+
+    /* set up the arguments */
+    args.object.name = Cur_filename;
+    (void) memmove((char *) &args.object.dir,(char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
+                       xdr_REMOVE3args, (char *) &args,
+                       xdr_REMOVE3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                               "%s: remove call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: remove call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_remove */
+
+
+static int
+op_rmdir(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    RMDIR3args         args;
+    RMDIR3res          reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[RMDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.object.name = Cur_file_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
+                       xdr_RMDIR3args, (char *) &args,
+                       xdr_RMDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                               "%s: rmdir call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rmdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rmdir */
+
+
+static int
+op_rename(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target name */
+    RENAME3args                args;
+    RENAME3res         reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[RENAME];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    target_fileinfo_ptr = randfh(RENAME, 0, 0, Nonexistent,
+                                Sfs_non_io_file);
+
+    args.from.name = Cur_file_ptr->file_name;
+    (void) sprintf(target_fileinfo_ptr->file_name, Filespec,
+                  target_fileinfo_ptr->unique_num);
+    args.to.name = target_fileinfo_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           target_fileinfo_ptr->state = Exists;
+           (void) memmove((char *) &target_fileinfo_ptr->fh3,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+           target_fileinfo_ptr->attributes3 = Cur_file_ptr->attributes3;
+           target_fileinfo_ptr->size = fh_size(Cur_file_ptr);
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: rename call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rename call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rename */
+
+
+static int
+op_link(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target */
+    LINK3args          args;
+    LINK3res           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[LINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(LINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.file, (char *) &target_fileinfo_ptr->fh3,
+               sizeof (nfs_fh3));
+    (void) memmove((char *) &args.link.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.link.name = Cur_filename;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LINK,
+                       xdr_LINK3args, (char *) &args,
+                       xdr_LINK3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &target_fileinfo_ptr->fh3,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           target_fileinfo_ptr->attributes3.nlink++;
+           Cur_file_ptr->attributes3 = target_fileinfo_ptr->attributes3;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: link call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: link call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_link */
+
+
+static int
+op_readdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READDIR3args       args;
+    READDIR3res                reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        i;
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+    bool_t             hit_eof;
+       /* array of entries */
+    entry3             entry_stream[SFS_MAXDIRENTS];
+    entry3             *entries;               /* ptr to the dir entry */
+
+    op_ptr = &Ops[READDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    args.count = DEFAULT_MAX_BUFSIZE;
+
+    /* Have lower layers fill in the data directly.  */
+    (void) memset((char *) &reply, '\0', sizeof (reply));
+    (void) memset((char *) entry_stream, '\0',
+                                       sizeof (entry3) * SFS_MAXDIRENTS);
+    reply.resok.count = SFS_MAXDIRENTS;
+    reply.resok.reply.entries = entry_stream;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIR,
+                       xdr_READDIR3args, (char *) &args,
+                       xdr_READDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+
+           if (DEBUG_CHILD_RPC) {
+               hit_eof = reply.resok.reply.eof;
+               entries = reply.resok.reply.entries;
+               for (i = 0; i < reply.resok.count; i++) {
+                   (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
+                                   sfs_Myname, hit_eof, entries[i].name);
+               }
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                               "%s: readdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readdir */
+
+
+static int
+op_readdirplus(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READDIRPLUS3args   args;
+    READDIRPLUS3res    reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        i;
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+    bool_t             hit_eof;
+       /* array of entries */
+    entryplus3         entry_stream[SFS_MAXDIRENTS];
+    entryplus3         *entries;
+
+    op_ptr = &Ops[READDIRPLUS];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    (void) memset((char *) entry_stream, '\0',
+                               sizeof (entryplus3) * SFS_MAXDIRENTS);
+    args.dircount = DEFAULT_MAX_BUFSIZE;
+    args.maxcount = DEFAULT_MAX_BUFSIZE;
+
+    /* Have lower layers fill in the data directly.  */
+    reply.resok.count = SFS_MAXDIRENTS;
+    reply.resok.reply.entries = entry_stream;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIRPLUS,
+                       xdr_READDIRPLUS3args, (char *) &args,
+                       xdr_READDIRPLUS3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+
+           if (DEBUG_CHILD_RPC) {
+               hit_eof = reply.resok.reply.eof;
+               entries = reply.resok.reply.entries;
+               for (i = 0; i < reply.resok.count; i++) {
+                   (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
+                                   sfs_Myname, hit_eof, entries[i].name);
+               }
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                               "%s: readdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readdirplus */
+
+
+static int
+op_fsstat(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    FSSTAT3args                args;
+    FSSTAT3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[FSSTAT];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_FSSTAT,
+                       xdr_FSSTAT3args, (char *) &args,
+                       xdr_FSSTAT3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: fsstat call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_fsstat */
+
+
+static int
+op_fsinfo(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    FSINFO3args                args;
+    FSINFO3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[FSINFO];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_FSINFO,
+                       xdr_FSINFO3args, (char *) &args,
+                       xdr_FSINFO3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: fsinfo call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_fsinfo */
+
+
+static int
+op_pathconf(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    PATHCONF3args      args;
+    PATHCONF3res       reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[PATHCONF];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_PATHCONF,
+                       xdr_PATHCONF3args, (char *) &args,
+                       xdr_PATHCONF3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: pathconf call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_pathconf */
+
+
+static int
+op_commit(void)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int32_t                    size;           /* size of data write */
+    COMMIT3args                        args;
+    COMMIT3res                 reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[COMMIT];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+    args.count = Cur_file_ptr->attributes3.size._p._l;
+    size = args.count;
+
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
+                               xdr_COMMIT3args, (char *) &args,
+                               xdr_COMMIT3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.file_wcc.after.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+
+           if (DEBUG_CHILD_RPC) {
+               (void) fprintf(stderr, "%s: WRITE %s %ld bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: write call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: write call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+
+    return(ret);
+
+} /* op_commit */
+
+
+#define LAD_RETRIABLE(stat) (((stat) == RPC_TIMEDOUT) || ((stat) == RPC_CANTDECODERES))
+
+/*
+ * Reliably lookup a file in the current directory
+ * Return:
+ *     -1      RPC error
+ *     1       File doesn't exist
+ *     0       File exists
+ */
+int
+lad_lookup(sfs_fh_type *file_ptr, char *name)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_lookup: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+        (void) memmove((char *) &args.what.dir, (char *) &file_ptr->dir->fh3,
+                                                       sizeof (nfs_fh3));
+       args.what.name = name;
+        (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_lookup(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status == NFS3ERR_NOENT) {
+       return(1);
+    }
+
+    if (reply.status != NFS3_OK) {
+       (void) fprintf(stderr, "lad_lookup(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+       return(-1);
+    }
+
+    file_ptr->state = Exists;
+    (void) memmove((char *) &file_ptr->fh3,
+                       (char *) &reply.resok.object,
+                       sizeof (nfs_fh3));
+    (void) strcpy(file_ptr->file_name, name);
+    (void) memmove((char *) &file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (file_ptr->attributes3));
+    file_ptr->size = fh_size(file_ptr);
+    return(0);
+}
+
+/*
+ * Reliably remove a file in the current directory
+ */
+int
+lad_remove(sfs_fh_type *file_ptr, char *name)
+{
+    REMOVE3args         args;
+    REMOVE3res          reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does exist
+     */
+    if (file_ptr->attributes3.type == NF3DIR)
+       return (lad_rmdir(file_ptr, name));
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_remove: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.object.name = name;
+       (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
+                       sizeof(nfs_fh3));
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
+                        xdr_REMOVE3args, (char *) &args,
+                        xdr_REMOVE3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_remove(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_remove(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably remove a directory in the current directory
+ */
+int
+lad_rmdir(sfs_fh_type *file_ptr, char *name)
+{
+    RMDIR3args          args;
+    RMDIR3res           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does exist and is empty
+     */
+    if (file_ptr->attributes3.type != NF3DIR)
+       return (lad_remove(file_ptr, name));
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_rmdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.object.name = name;
+        (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
+                        xdr_RMDIR3args, (char *) &args,
+                        xdr_RMDIR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_rmdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_rmdir(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably create a symlink in the current directory
+ */
+int
+lad_symlink(sfs_fh_type *file_ptr, char *target, char *name)
+{
+    SYMLINK3args        args;
+    SYMLINK3res         reply;                 /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_symlink: %lx[%lx] %s -> %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name, target);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+         args.where.name = name;
+
+       (void) strcpy(sym_data, "./");
+       (void) strcat(sym_data, target);
+       args.symlink.symlink_attributes.size.set_it = TRUE;
+       args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
+       args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
+       args.symlink.symlink_data = sym_data;
+
+       args.symlink.symlink_attributes.mode.set_it = TRUE;
+       args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
+       args.symlink.symlink_attributes.uid.set_it = TRUE;
+       args.symlink.symlink_attributes.uid.uid = Cur_uid;
+       args.symlink.symlink_attributes.gid.set_it = TRUE;
+       args.symlink.symlink_attributes.gid.gid = Cur_gid;
+       args.symlink.symlink_attributes.atime.set_it = TRUE;
+       args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
+       args.symlink.symlink_attributes.atime.atime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.symlink.symlink_attributes.mtime.set_it = TRUE;
+       args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.symlink.symlink_attributes.mtime.mtime.nseconds =
+                                                Cur_time.usec * 1000;
+
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
+                        xdr_SYMLINK3args, (char *) &args,
+                        xdr_SYMLINK3res, (char *) &reply,
+                       Nfs_timers[Init]);
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_symlink(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_symlink(%s, %s) NFS call failed : %s\n",
+                       target, name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    /*
+     * SYMLINK may not return a fh. If we try to
+     * access this symlink (eg, remove(), readlink())
+     * before we do a lookup, we won't have a fh to use.
+     * So, we do a lookup call here.
+     * If it fails, we fill in what we can.
+     */  
+    return (lad_lookup(file_ptr, name));
+}
+
+/*
+ * Reliably create a directory in the current directory
+ */
+int
+lad_mkdir(sfs_fh_type *file_ptr, char *name)
+{
+    MKDIR3args          args;
+    MKDIR3res           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_mkdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+       args.where.name = name;
+       args.attributes.mode.set_it = TRUE;
+       args.attributes.mode.mode = (NFSMODE_DIR | 0777);
+       args.attributes.uid.set_it = TRUE;
+       args.attributes.uid.uid = Cur_uid;
+       args.attributes.gid.set_it = TRUE;
+       args.attributes.gid.gid = Cur_gid;
+       args.attributes.size.set_it = TRUE;
+       args.attributes.size.size._p._u = 0;
+       args.attributes.size.size._p._l = 512;
+       args.attributes.atime.set_it = TRUE;
+       args.attributes.atime.atime.seconds = Cur_time.esec;
+       args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+       args.attributes.mtime.set_it = TRUE;
+       args.attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
+                        xdr_MKDIR3args, (char *) &args,
+                        xdr_MKDIR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_mkdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFS3ERR_EXIST)
+       return(1);
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_mkdir(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+       /*
+        * If the first mkdir suceeded but the reply as dropped and
+        * was retransmitted, we still need to lookup the attributes
+        */
+       if (lad_lookup(file_ptr, name))
+          return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh3,
+                   (char *) &reply.resok.obj.handle,
+                   sizeof (nfs_fh3));
+       (void) strcpy(file_ptr->file_name, name);
+       (void) memmove((char *) &file_ptr->attributes3,
+                   (char *) &reply.resok.obj_attributes.attr,
+                   sizeof(file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+    }
+    file_ptr->state = Empty_dir;
+
+    return(0);
+}
+
+/*
+ * Reliably commit a file
+ */
+static int
+lad_commit(sfs_fh_type *file_ptr)
+{
+    COMMIT3args                        args;
+    COMMIT3res                 reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_commit: %lx[%lx]\n",
+                       sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir);
+       (void) fflush(stderr);
+    }
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+    args.count = file_ptr->attributes3.size._p._l;
+
+    /* CONSTCOND */
+    while (1) {
+        rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
+                               xdr_COMMIT3args, (char *) &args,
+                               xdr_COMMIT3res, (char *) &reply,
+                               Nfs_timers[Init]);
+        if (rpc_stat == RPC_SUCCESS) 
+           break;
+        if (rpc_stat != RPC_TIMEDOUT) {
+           (void) fprintf(stderr, "lad_commit() RPC call failed : %s\n",
+                               clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    return(0);
+}
+
+/*
+ * Reliably write a file in the current directory
+ */
+int
+lad_write(sfs_fh_type *file_ptr, int32_t offset, int32_t length)
+{
+    static char                        *buf = NULL;    /* the data buffer */
+    int32_t                    size;           /* size of data write */
+    int32_t                    cur_cnt;
+    WRITE3args                  args;
+    WRITE3res                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    int                                async = 1;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_write: %lx[%lx] %ld %ld\n",
+                       sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, offset, length);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does exist
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+
+    /*
+     * If a short file write don't bother with the commit, just write sync.
+     */
+    if (length <= Bytes_per_block)
+       async = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
+                sizeof (nfs_fh3));
+    args.offset._p._u = 0;
+    args.offset._p._l = offset;
+    if (async)
+           args.stable = UNSTABLE;
+    else
+           args.stable = FILE_SYNC;
+
+    size = Bytes_per_block;
+    for (cur_cnt = 0; cur_cnt < length; cur_cnt += size) {
+       if ((cur_cnt + size) > length)
+               size = length - cur_cnt;
+
+       if (size == 0)
+           break;
+
+       args.count = size;
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* make the call now */
+        /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
+                                xdr_WRITE3args, (char *) &args,
+                                xdr_WRITE3res, (char *) &reply,
+                               Nfs_timers[Init]);
+
+           if (rpc_stat == RPC_SUCCESS) 
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_write() RPC call failed : %s\n",
+                               clnt_sperrno(rpc_stat));
+           }
+           if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+           }
+       }
+       if (reply.status != NFS3_OK) {
+           (void) fprintf(stderr, "lad_write() NFS call failed : %s\n",
+                       nfs3_strerror(reply.status));
+           return(-1);
+       }
+       file_ptr->state = Exists;
+        (void) memmove((char *) &file_ptr->attributes3,
+                                (char *) &reply.resok.file_wcc.after.attr,
+                                sizeof (file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+
+        args.offset._p._l += size;
+    }
+
+    if (async)
+       (void) lad_commit(file_ptr);
+    return(0);
+}
+
+/*
+ * Reliably create a file in the current directory
+ */
+int
+lad_create(sfs_fh_type *file_ptr, char *name)
+{
+    CREATE3args         args;
+    CREATE3res          reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_create: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+       args.where.name = name;
+       args.how.mode = UNCHECKED;
+       args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
+       args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+       args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+       args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.atime.atime.seconds =
+                                               Cur_time.esec;
+       args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.mtime.mtime.seconds =
+                                               Cur_time.esec;
+       args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.size.size._p._u =
+                                               (uint32_t) 0;
+       args.how.createhow3_u.obj_attributes.size.size._p._l =
+                                               (uint32_t) 0;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
+                        xdr_CREATE3args, (char *) &args,
+                        xdr_CREATE3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_create(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFS3ERR_EXIST) {
+       return(1);
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_create(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+        /*
+         * If the first create suceeded but the reply as dropped and
+         * was retransmitted, we still need to lookup the attributes
+         */
+        if (lad_lookup(file_ptr, name))
+           return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh3,
+                   (char *) &reply.resok.obj.handle,
+                   sizeof (nfs_fh3));
+       (void) strcpy(file_ptr->file_name, name);
+       (void) memmove((char *) &file_ptr->attributes3,
+                   (char *) &reply.resok.obj_attributes.attr,
+                   sizeof(file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+    }
+
+    file_ptr->state = Exists;
+    /*
+     * Directories are created as Empty_dir, when a file is created it
+     * becomes an Exists.
+     */
+    file_ptr->dir->state = Exists;
+
+    return(0);
+}
+
+/*
+ * Reliably set the size of a file in the current directory
+ */
+int
+lad_truncate(sfs_fh_type *file_ptr, int32_t size)
+{
+    SETATTR3args        args;
+    SETATTR3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    /*
+     * This function presumes that the file name already exists
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_truncate: %lx[%lx] %ld\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, size);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /*
+        * set up the arguments
+        * Set the mode and times as well
+        */
+       (void) memmove((char *) &args.object, (char *) &file_ptr->fh3,
+                                                        sizeof (nfs_fh3));
+       args.new_attributes.mode.set_it = TRUE;
+       args.new_attributes.mode.mode = (uint32_t) 0666;
+       args.new_attributes.uid.set_it = FALSE;
+       args.new_attributes.uid.uid = (uint32_t) -1;
+       args.new_attributes.gid.set_it = FALSE;
+       args.new_attributes.gid.gid = (uint32_t) -1;
+       args.new_attributes.size.set_it = TRUE;
+       args.new_attributes.size.size._p._u = 0;
+       args.new_attributes.size.size._p._l = size;
+       args.new_attributes.atime.set_it = TRUE;
+       args.new_attributes.atime.atime.seconds = Cur_time.esec;
+       args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+       args.new_attributes.mtime.set_it = TRUE;
+       args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+       args.guard.check = FALSE;
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
+                        xdr_SETATTR3args, (char *) &args,
+                        xdr_SETATTR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void)fprintf(stderr,
+                               "lad_truncate(%ld) RPC call failed : %s\n",
+                               size, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status != NFS3_OK) {
+       (void) fprintf(stderr, "lad_truncate(%ld) NFS call failed : %s\n",
+                       size, nfs3_strerror(reply.status));
+       return(-1);
+    }
+    (void) memmove(&file_ptr->attributes3,
+                   &reply.resok.obj_wcc.after.attr,
+                   sizeof (file_ptr->attributes3));
+    file_ptr->size = fh_size(file_ptr);
+
+    return(0);
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "RFS timeout");
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/* sfs_3_ops.c */
diff --git a/TBBT/trace_play/sfs_3_ops.c.org b/TBBT/trace_play/sfs_3_ops.c.org
new file mode 100644 (file)
index 0000000..57cbb57
--- /dev/null
@@ -0,0 +1,2701 @@
+#ifndef lint
+static char sfs_3_opsSid[] = "@(#)sfs_3_ops.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_3_ops.c ---------------------
+ *
+ *      RPC routines to implement the NFS protocol.
+ *
+ *.Local Routines
+ *     int op_null(void)
+ *     int op_getattr(void)
+ *     int op_setattr(int)
+ *     int op_lookup(void)
+ *     int op_access(void)
+ *     int op_readlink(void)
+ *     int op_read(int)
+ *     int op_write(int, int, stable_how)
+ *     int op_create(void)
+ *     int op_mkdir(void);
+ *     int op_symlink(void);
+ *     int op_mknod(void);
+ *     int op_remove(void);
+ *     int op_rmdir(void);
+ *     int op_rename(void);
+ *     int op_link(void);
+ *     int op_readdir(void);
+ *     int op_readdirplus(void);
+ *     int op_fsstat(void);
+ *     int op_fsinfo(void);
+ *     int op_pathconf(void);
+ *     int op_commit(void);
+ *
+ *.Revision_History
+ *     30-Jun-94       ChakChung Ng    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+/*
+ * --------------------  Local NFS ops function --------------------
+ */
+static int op_null(void);
+static int op_getattr(void);
+static int op_setattr(int);
+static int op_lookup(void);
+static int op_access(void);
+static int op_readlink(void);
+static int op_read(int);
+static int op_write(int, int, stable_how);
+static int op_create(void);
+static int op_mkdir(void);
+static int op_symlink(void);
+static int op_mknod(void);
+static int op_remove(void);
+static int op_rmdir(void);
+static int op_rename(void);
+static int op_link(void);
+static int op_readdir(void);
+static int op_readdirplus(void);
+static int op_fsstat(void);
+static int op_fsinfo(void);
+static int op_pathconf(void);
+static int op_commit(void);
+static int op_nosys(void);
+static char *nfs3_strerror(int);
+
+
+/*
+ * --------------------  NFS ops vector --------------------
+ */
+/*
+ * per operation information
+ */
+static sfs_op_type nfsv3_Ops[] = {
+
+/* name        mix   function         op    call  no  req  req  req  results */
+/*             pcnt                  class  targ call pcnt cnt  targ         */
+
+ { "null",        0, op_null,        Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "getattr",    11, op_getattr,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "setattr",     1, op_setattr,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "root",        0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "lookup",     27, op_lookup,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readlink",    7, op_readlink,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "read",       18, op_read,        Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "wrcache",     0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "write",       9, op_write,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "create",      1, op_create,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "remove",      1, op_remove,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rename",      0, op_rename,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "link",        0, op_link,        Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "symlink",     0, op_symlink,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "mkdir",       0, op_mkdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "rmdir",       0, op_rmdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdir",     2, op_readdir,     Read,    0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsstat",      1, op_fsstat,             Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "access",      7, op_access,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "commit",      5, op_commit,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "fsinfo",      1, op_fsinfo,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "mknod",       0, op_mknod,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "pathconf",    0, op_pathconf,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
+ { "readdirplus", 9, op_readdirplus, Read,   0,  0,  0.0,  0,   0,  { 0, }},
+ { "TOTAL",     100, 0,              Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
+};
+
+sfs_op_type *Ops;
+
+/*
+ * --------------------  RPC routines for NFS protocol --------------------
+ */
+
+void
+init_ops(void)
+{
+    Ops = nfsv3_Ops;
+    nfs_version = NFS_V3;
+}
+
+/*
+ * The routines below attempt to do over-the-wire operations.
+ * Each op tries to cause one or more of a particular
+ * NFS operation to go over the wire.  OPs return the success
+ * of their NFS call(s).  Each OP records how many calls it
+ * actually made in global data.
+ *
+ * An array of file information is kept for files existing in
+ * the test directory.  File handles, attributes, names, etc
+ * are stored in this array.
+ *
+ */
+
+/*
+ * Generic catch all for operations not covered by this protocol.
+ */
+static int
+op_nosys(void)
+{
+    Ops[TOTAL].results.bad_calls++;
+    return(0);
+}
+
+static int
+op_null(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[NULLCALL];
+    ret = 0;
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_NULL,
+                       xdr_void, (char *)0, xdr_void, (char *)0,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: null_op call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_null */
+
+
+static int
+op_getattr(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    GETATTR3args       args;           /* fh to do op on */
+    GETATTR3res                reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[GETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+                                                       sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_GETATTR,
+                       xdr_GETATTR3args, (char *) &args,
+                       xdr_GETATTR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: getattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: getattr call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_getattr */
+
+
+/*
+ * perform an RPC setattr operation.  If 'truncate_size' is non-negative,
+ * truncate the file to that size.
+ */
+static int
+op_setattr(
+    int                truncate_size)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    SETATTR3args       args;
+    SETATTR3res                reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[SETATTR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+                                                       sizeof (nfs_fh3));
+    args.new_attributes.mode.set_it = TRUE;
+    args.new_attributes.mode.mode = (uint32_t) 0666;
+    args.new_attributes.uid.set_it = FALSE;
+    args.new_attributes.uid.uid = (uint32_t) -1;
+    args.new_attributes.gid.set_it = FALSE;
+    args.new_attributes.gid.gid = (uint32_t) -1;
+    args.new_attributes.size.set_it = FALSE;
+    args.new_attributes.size.size._p._u = (uint32_t) ~0;
+    args.new_attributes.size.size._p._l = (uint32_t) -1;
+    args.new_attributes.atime.set_it = TRUE;
+    args.new_attributes.atime.atime.seconds = Cur_time.esec;
+    args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+    args.new_attributes.mtime.set_it = TRUE;
+    args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+    args.guard.check = FALSE;
+
+    /* handle file truncations */
+    if (truncate_size >= 0) {
+       args.new_attributes.size.set_it = TRUE;
+       args.new_attributes.size.size._p._u = (uint32_t) 0;
+       if (truncate_size > Cur_file_ptr->attributes3.size._p._l)
+           args.new_attributes.size.size._p._l = (uint32_t) 0;
+       else
+           args.new_attributes.size.size._p._l =
+               (uint32_t) Cur_file_ptr->attributes3.size._p._l -
+                                                               truncate_size;
+    }
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
+                       xdr_SETATTR3args, (char *) &args,
+                       xdr_SETATTR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_wcc.after.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: setattr call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: setattr call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_setattr */
+
+
+static int
+op_lookup(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[LOOKUP];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.what.dir, (char *) &Cur_file_ptr->dir->fh3,
+                                                       sizeof (nfs_fh3));
+    args.what.name = Cur_filename;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.object,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           /* We do lookup Nonexistent and this is not an error */
+           if (reply.status != NFS3ERR_NOENT ||
+                       Cur_file_ptr->state != Nonexistent) {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                       "%s: lookup call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+               }
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: lookup call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_lookup */
+
+
+static int
+op_access(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    ACCESS3args                args;
+    ACCESS3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[ACCESS];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->dir->fh3,
+                               sizeof (nfs_fh3));
+    args.access = ACCESS3_MODIFY;
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_ACCESS,
+                       xdr_ACCESS3args, (char *) &args,
+                       xdr_ACCESS3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: access call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: access call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_access */
+
+
+static int
+op_readlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READLINK3args      args;                   /* the args */
+    READLINK3res       reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[READLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    /*
+     * Note: this symlink may be bogus because SYMLINK does
+     * not return a symlink ... only a status.  So unless we have
+     * done a LOOKUP on this guy, the symlink will probably be bad.
+     * If it is bad it shows up as a symlink error in the results.
+     */
+    (void) memmove((char *) &args.symlink,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /* Have lower layers fill in the data directly. */
+    reply.resok.data = sym_data;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READLINK,
+                       xdr_READLINK3args, (char *) &args,
+                       xdr_READLINK3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           if (DEBUG_CHILD_RPC) {
+               (void) fprintf(stderr, "%s: READLINK on %s returned %s\n",
+                                   sfs_Myname, Cur_filename, sym_data);
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: readlink call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readlink */
+
+
+/*
+ * perform an RPC read operation of length 'xfer_size'
+ */
+static int
+op_read(
+    int                        xfer_size)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int                                cur_cnt;
+    int                                max_cnt;        /* packet ctrs */
+    char                       buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
+    READ3args                  args;
+    READ3res                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                size;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[READ];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /*
+     * Don't allow a read of less than one block size
+     */
+    if (xfer_size < Bytes_per_block)
+       xfer_size = Bytes_per_block;
+
+    /*
+     * randomly choose an offset that is a multiple of the block size
+     * and constrained by making the transfer fit within the file
+     */
+    args.offset._p._u = 0;
+    if (Cur_file_ptr->attributes3.size._p._l > xfer_size)
+       args.offset._p._l = Bytes_per_block * (sfs_random() %
+                       (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
+                       / Bytes_per_block) + 1));
+    else
+       args.offset._p._l = 0;
+
+    /* Have lower layers fill in the data directly.  */
+    reply.resok.data.data_len = 0;
+    reply.resok.data.data_val = buf;
+
+    /* first read the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block -1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       args.count = size;
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "read: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_READ,
+                               xdr_READ3args, (char *) &args,
+                               xdr_READ3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = (rpc_stat == RPC_SUCCESS && reply.status == NFS3_OK)
+                           ? reply.resok.data.data_len : 0;
+           Dump_offset = args.offset._p._l;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS3_OK) {
+                   Cur_file_ptr->state = Exists;
+                   (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.file_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   size = reply.resok.data.data_len;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: READ %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+                   args.offset._p._l += size;
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: read call NFS error %s on file %d\n",
+                                       sfs_Myname,
+                                       nfs3_strerror(reply.status),
+                                       Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                               "%s: read call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for reading max_cnt packets */
+    } /* for buffers and fragments */
+    return(ret);
+
+} /* op_read */
+
+char *
+init_write_buffer(
+    void)
+{
+    uint32_t *bp;
+    static uint32_t write_buf[DEFAULT_MAX_BUFSIZE / sizeof(uint32_t)];
+    uint32_t *be  = write_buf + (sizeof(write_buf) /
+                                                       sizeof(uint32_t));
+
+    if (write_buf[0] != (uint32_t)0xdeadbeef) {
+        for (bp = write_buf; bp < be; bp++)
+            *bp = (uint32_t)0xdeadbeef;
+    }
+    return (char *)write_buf;
+}
+
+
+/*
+ * Perform and RPC write operation of length 'xfer_size'.  If 'append_flag'
+ * is true, then write the data to the end of the file.
+ *
+ * If the stab_flag is set to UNSTABLE we issue the requests and then
+ * issue a op_commit to sync the data.
+ */
+static int
+op_write(
+    int                        xfer_size,
+    int                        append_flag,
+    stable_how         stab_flag)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    static char                        *buf = NULL;    /* the data buffer */
+    unsigned int               size;           /* size of data write */
+    int                                cur_cnt;        /* controls # NFS calls */
+    int                                max_cnt;
+    WRITE3args                 args;
+    WRITE3res                  reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                j;
+    int                                ret;            /* ret val == call success */
+
+    /*
+     * For now we treat DATA_SYNC to be the same as FILE_SYNC.
+     */
+    if (stab_flag == DATA_SYNC)
+       stab_flag = FILE_SYNC;
+
+    /*
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+
+    op_ptr = &Ops[WRITE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = 0;
+    if (append_flag == 1) {
+       args.offset._p._l = Cur_file_ptr->attributes3.size._p._l;
+    } else {
+       /*
+        * randomly choose an offset that is a multiple of the block size
+        * and constrained by making the transfer fit within the file
+        */
+       if (Cur_file_ptr->attributes3.size._p._l > xfer_size) {
+           args.offset._p._l = Bytes_per_block * (sfs_random() %
+                           (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
+                           / Bytes_per_block) + 1));
+       } else
+           args.offset._p._l = 0;
+    }
+
+    /* stab_flag has to be set in op() in sfs_3_chd.c */
+    args.stable = stab_flag;
+
+    /* first write the whole buffers, then the fragment */
+    for (j = 0; j < 2; j++) {
+
+       if (j == 0) {
+           size = Bytes_per_block;
+           max_cnt = xfer_size / Bytes_per_block;
+       } else {
+           /* 1KB - (Kb_per_block - 1) KB fragment */
+           size = xfer_size % Bytes_per_block;
+           max_cnt = 1;
+       }
+       if (size == 0)
+           continue;
+
+       args.count = size;
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* check our stats to see if this would overflow */
+       if (!Timed_run) {
+           if (op_ptr->target_calls > 0) {
+               if ((op_ptr->results.good_calls + max_cnt)
+                    > op_ptr->target_calls) {
+                   max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+               }
+           }
+       }
+
+       if (DEBUG_CHILD_RPC) {
+           (void) fprintf(stderr, "write: %d buffers\n", max_cnt);
+           (void) fflush(stderr);
+       }
+
+       /* make the call(s) now */
+       for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
+
+           if (DEBUG_CHILD_RPC) {
+(void) fprintf(stderr, "%s: WRITE %s offset %u count %lu stable %d\n",
+sfs_Myname, Cur_filename, args.offset._p._l, args.count, args.stable);
+               (void) fflush(stderr);
+           }
+
+           /* capture length for possible dump */
+           Dump_length = fh_size(Cur_file_ptr);
+           sfs_gettime(&start);
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
+                               xdr_WRITE3args, (char *) &args,
+                               xdr_WRITE3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+           sfs_gettime(&stop);
+           Cur_time = stop;
+
+           /* capture count and offset for possible dump */
+           Dump_count = args.data.data_len;
+           Dump_offset = args.offset._p._l;
+
+           if (rpc_stat == RPC_SUCCESS) {
+               if (reply.status == NFS3_OK) {
+                   Cur_file_ptr->state = Exists;
+                   (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &reply.resok.file_wcc.after.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+                   Cur_file_ptr->size = fh_size(Cur_file_ptr);
+                   args.offset._p._l += size;
+
+                   if (DEBUG_CHILD_RPC) {
+                       (void) fprintf(stderr, "%s: WRITE %s %d bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+                       (void) fflush(stderr);
+                   }
+               } else {
+                   if (DEBUG_CHILD_ERROR) {
+                        (void) fprintf(stderr,
+                               "%s: write call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+                   }
+               }
+               sfs_elapsedtime(op_ptr, &start, &stop);
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+               ret++;
+           } else {
+               if (DEBUG_CHILD_ERROR) {
+                    (void) fprintf(stderr,
+                               "%s: write call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+               }
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+           }
+       } /* for writing max_cnt packets */
+    } /* for buffers and fragments */
+
+    /*
+     * If we have not gotten an error and we were asked for an async write
+     * send a commit operation.
+     */
+    if (ret && stab_flag != FILE_SYNC)
+       ret += op_commit();
+
+    return(ret);
+
+} /* op_write */
+
+
+static int
+op_create(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    CREATE3args                args;
+    CREATE3res         reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[CREATE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.how.mode = UNCHECKED;
+    args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
+    args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+    args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+    args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.atime.atime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+    args.how.createhow3_u.obj_attributes.size.size._p._u = (uint32_t) 0;
+    args.how.createhow3_u.obj_attributes.size.size._p._l = (uint32_t) 0;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
+                       xdr_CREATE3args, (char *) &args,
+                       xdr_CREATE3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: create call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: create call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_create */
+
+
+static int
+op_mkdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    MKDIR3args         args;
+    MKDIR3res          reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[MKDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.attributes.mode.set_it = TRUE;
+    args.attributes.mode.mode = (NFSMODE_DIR | 0777);
+    args.attributes.uid.set_it = TRUE;
+    args.attributes.uid.uid = Cur_uid;
+    args.attributes.gid.set_it = TRUE;
+    args.attributes.gid.gid = Cur_gid;
+    args.attributes.size.set_it = TRUE;
+    args.attributes.size.size._p._u = 0;
+    args.attributes.size.size._p._l = 512;
+    args.attributes.atime.set_it = TRUE;
+    args.attributes.atime.atime.seconds = Cur_time.esec;
+    args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+    args.attributes.mtime.set_it = TRUE;
+    args.attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
+                       xdr_MKDIR3args, (char *) &args,
+                       xdr_MKDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+            Cur_file_ptr->state = Empty_dir;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: mkdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: mkdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_mkdir */
+
+
+static int
+op_symlink(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target file */
+    SYMLINK3args       args;
+    SYMLINK3res                reply;                  /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[SYMLINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(SYMLINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+
+    (void) strcpy(sym_data, "./");
+    (void) strcat(sym_data, target_fileinfo_ptr->file_name);
+    args.symlink.symlink_attributes.size.set_it = TRUE;
+    args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
+    args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
+    args.symlink.symlink_data = sym_data;
+
+    args.symlink.symlink_attributes.mode.set_it = TRUE;
+    args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
+    args.symlink.symlink_attributes.uid.set_it = TRUE;
+    args.symlink.symlink_attributes.uid.uid = Cur_uid;
+    args.symlink.symlink_attributes.gid.set_it = TRUE;
+    args.symlink.symlink_attributes.gid.gid = Cur_gid;
+    args.symlink.symlink_attributes.atime.set_it = TRUE;
+    args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
+    args.symlink.symlink_attributes.atime.atime.nseconds =
+                                               Cur_time.usec * 1000;
+    args.symlink.symlink_attributes.mtime.set_it = TRUE;
+    args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
+    args.symlink.symlink_attributes.mtime.mtime.nseconds =
+                                               Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
+                       xdr_SYMLINK3args, (char *) &args,
+                       xdr_SYMLINK3res, (char *) &reply,
+                       ((int)Current_test_phase < (int)Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           /*
+            * SYMLINK doesn't return a fh. If we try to access this symlink
+            * (eg, remove(), readlink()) before we do a lookup, we won't have
+            * a fh to use. So, we do a lookup call here. If it fails, we fill
+            * in what we can.
+            */
+           Cur_file_ptr->state = Exists;
+           if (op_lookup() == 0) {
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               Cur_file_ptr->attributes3.type = NF3LNK;
+               Cur_file_ptr->attributes3.mode = (NFSMODE_LNK|0777);
+               Cur_file_ptr->attributes3.uid = Cur_uid;
+               Cur_file_ptr->attributes3.gid = Cur_gid;
+               Cur_file_ptr->attributes3.atime.seconds = Cur_time.esec;
+               Cur_file_ptr->attributes3.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+               Cur_file_ptr->attributes3.mtime =
+                       Cur_file_ptr->attributes3.atime;
+           } else
+               ret++;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: symlink call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: symlink call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_symlink */
+
+
+static int
+op_mknod(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    MKNOD3args         args;
+    MKNOD3res          reply;
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[MKNOD];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.where.name = Cur_filename;
+    args.what.type = NF3FIFO;
+    args.what.mknoddata3_u.pipe_attributes.mode.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mode.mode = (NFSMODE_FIFO | 0777);
+    args.what.mknoddata3_u.pipe_attributes.uid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.uid.uid = Cur_uid;
+    args.what.mknoddata3_u.pipe_attributes.gid.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.gid.gid = Cur_gid;
+    args.what.mknoddata3_u.pipe_attributes.size.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._u = (uint32_t) 0;
+    args.what.mknoddata3_u.pipe_attributes.size.size._p._l =
+                                                       (uint32_t) 512;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+    args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.seconds =
+                                                               Cur_time.esec;
+    args.what.mknoddata3_u.pipe_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_MKNOD,
+                       xdr_MKNOD3args, (char *) &args,
+                       xdr_MKNOD3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &reply.resok.obj.handle,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.obj_attributes.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: mknod call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: mknod call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_mknod */
+
+
+static int
+op_remove(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    REMOVE3args                args;
+    REMOVE3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[REMOVE];
+    ret = 0;
+
+    /* set up the arguments */
+    args.object.name = Cur_filename;
+    (void) memmove((char *) &args.object.dir,(char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
+                       xdr_REMOVE3args, (char *) &args,
+                       xdr_REMOVE3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                               "%s: remove call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: remove call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_remove */
+
+
+static int
+op_rmdir(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    RMDIR3args         args;
+    RMDIR3res          reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[RMDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.object.name = Cur_file_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
+                       xdr_RMDIR3args, (char *) &args,
+                       xdr_RMDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                               "%s: rmdir call NFS error %s on file %d\n",
+                               sfs_Myname, nfs3_strerror(reply.status),
+                               Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rmdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rmdir */
+
+
+static int
+op_rename(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target name */
+    RENAME3args                args;
+    RENAME3res         reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[RENAME];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    target_fileinfo_ptr = randfh(RENAME, 0, 0, Nonexistent,
+                                Sfs_non_io_file);
+
+    args.from.name = Cur_file_ptr->file_name;
+    (void) sprintf(target_fileinfo_ptr->file_name, Filespec,
+                  target_fileinfo_ptr->unique_num);
+    args.to.name = target_fileinfo_ptr->file_name;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           target_fileinfo_ptr->state = Exists;
+           (void) memmove((char *) &target_fileinfo_ptr->fh3,
+                       (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+           target_fileinfo_ptr->attributes3 = Cur_file_ptr->attributes3;
+           target_fileinfo_ptr->size = fh_size(Cur_file_ptr);
+           Cur_file_ptr->state = Nonexistent;
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: rename call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: rename call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_rename */
+
+
+static int
+op_link(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    sfs_fh_type                *target_fileinfo_ptr;   /* target */
+    LINK3args          args;
+    LINK3res           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+
+    op_ptr = &Ops[LINK];
+    ret = 0;
+
+    /* set up the arguments */
+    target_fileinfo_ptr = randfh(LINK, 0, 0, Exists, Sfs_non_io_file);
+    (void) memmove((char *) &args.file, (char *) &target_fileinfo_ptr->fh3,
+               sizeof (nfs_fh3));
+    (void) memmove((char *) &args.link.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.link.name = Cur_filename;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LINK,
+                       xdr_LINK3args, (char *) &args,
+                       xdr_LINK3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->fh3,
+                       (char *) &target_fileinfo_ptr->fh3,
+                       sizeof (nfs_fh3));
+           (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+           target_fileinfo_ptr->attributes3.nlink++;
+           Cur_file_ptr->attributes3 = target_fileinfo_ptr->attributes3;
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: link call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: link call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_link */
+
+
+static int
+op_readdir(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READDIR3args       args;
+    READDIR3res                reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        i;
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+    bool_t             hit_eof;
+       /* array of entries */
+    entry3             entry_stream[SFS_MAXDIRENTS];
+    entry3             *entries;               /* ptr to the dir entry */
+
+    op_ptr = &Ops[READDIR];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    args.count = DEFAULT_MAX_BUFSIZE;
+
+    /* Have lower layers fill in the data directly.  */
+    (void) memset((char *) &reply, '\0', sizeof (reply));
+    (void) memset((char *) entry_stream, '\0',
+                                       sizeof (entry3) * SFS_MAXDIRENTS);
+    reply.resok.count = SFS_MAXDIRENTS;
+    reply.resok.reply.entries = entry_stream;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIR,
+                       xdr_READDIR3args, (char *) &args,
+                       xdr_READDIR3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+
+           if (DEBUG_CHILD_RPC) {
+               hit_eof = reply.resok.reply.eof;
+               entries = reply.resok.reply.entries;
+               for (i = 0; i < reply.resok.count; i++) {
+                   (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
+                                   sfs_Myname, hit_eof, entries[i].name);
+               }
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                               "%s: readdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readdir */
+
+
+static int
+op_readdirplus(void)
+{
+    sfs_op_type                *op_ptr;                /* per operation info */
+    READDIRPLUS3args   args;
+    READDIRPLUS3res    reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        i;
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;                    /* ret val == call success */
+    bool_t             hit_eof;
+       /* array of entries */
+    entryplus3         entry_stream[SFS_MAXDIRENTS];
+    entryplus3         *entries;
+
+    op_ptr = &Ops[READDIRPLUS];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+    args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    (void) memset((char *) entry_stream, '\0',
+                               sizeof (entryplus3) * SFS_MAXDIRENTS);
+    args.dircount = DEFAULT_MAX_BUFSIZE;
+    args.maxcount = DEFAULT_MAX_BUFSIZE;
+
+    /* Have lower layers fill in the data directly.  */
+    reply.resok.count = SFS_MAXDIRENTS;
+    reply.resok.reply.entries = entry_stream;
+
+    /* make the call now */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIRPLUS,
+                       xdr_READDIRPLUS3args, (char *) &args,
+                       xdr_READDIRPLUS3res, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+
+           if (DEBUG_CHILD_RPC) {
+               hit_eof = reply.resok.reply.eof;
+               entries = reply.resok.reply.entries;
+               for (i = 0; i < reply.resok.count; i++) {
+                   (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
+                                   sfs_Myname, hit_eof, entries[i].name);
+               }
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: readdir call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                               "%s: readdir call RPC error %d on file %d\n",
+                   sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_readdirplus */
+
+
+static int
+op_fsstat(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    FSSTAT3args                args;
+    FSSTAT3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[FSSTAT];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_FSSTAT,
+                       xdr_FSSTAT3args, (char *) &args,
+                       xdr_FSSTAT3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: fsstat call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_fsstat */
+
+
+static int
+op_fsinfo(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    FSINFO3args                args;
+    FSINFO3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[FSINFO];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_FSINFO,
+                       xdr_FSINFO3args, (char *) &args,
+                       xdr_FSINFO3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: fsinfo call RPC error %d\n",
+                                               sfs_Myname, rpc_stat);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_fsinfo */
+
+
+static int
+op_pathconf(void)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    PATHCONF3args      args;
+    PATHCONF3res       reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+    int                        ret;            /* ret val == call success */
+
+    op_ptr = &Ops[PATHCONF];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_PATHCONF,
+                       xdr_PATHCONF3args, (char *) &args,
+                       xdr_PATHCONF3args, (char *) &reply,
+                       (Current_test_phase < Warmup_phase)
+                                ? Nfs_timers[Init]
+                                : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr,
+                       "%s: pathconf call RPC error %d on file %d\n",
+                       sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+    return(ret);
+
+} /* op_pathconf */
+
+
+static int
+op_commit(void)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int32_t                    size;           /* size of data write */
+    COMMIT3args                        args;
+    COMMIT3res                 reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    struct ladtime             start;
+    struct ladtime             stop;
+    int                                ret;            /* ret val == call success */
+
+    op_ptr = &Ops[COMMIT];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+    args.count = Cur_file_ptr->attributes3.size._p._l;
+    size = args.count;
+
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
+                               xdr_COMMIT3args, (char *) &args,
+                               xdr_COMMIT3res, (char *) &reply,
+                               (Current_test_phase < Warmup_phase)
+                                    ? Nfs_timers[Init]
+                                    : Nfs_timers[op_ptr->call_class]);
+    sfs_gettime(&stop);
+    Cur_time = stop;
+
+    if (rpc_stat == RPC_SUCCESS) {
+       if (reply.status == NFS3_OK) {
+           Cur_file_ptr->state = Exists;
+           (void) memmove((char *) &Cur_file_ptr->attributes3,
+                       (char *) &reply.resok.file_wcc.after.attr,
+                       sizeof(Cur_file_ptr->attributes3));
+           Cur_file_ptr->size = fh_size(Cur_file_ptr);
+
+           if (DEBUG_CHILD_RPC) {
+               (void) fprintf(stderr, "%s: WRITE %s %ld bytes\n",
+                                          sfs_Myname, Cur_filename, size);
+               (void) fflush(stderr);
+           }
+       } else {
+           if (DEBUG_CHILD_ERROR) {
+                (void) fprintf(stderr,
+                       "%s: write call NFS error %s on file %d\n",
+                       sfs_Myname, nfs3_strerror(reply.status),
+                       Cur_file_ptr->unique_num);
+           }
+       }
+       sfs_elapsedtime(op_ptr, &start, &stop);
+       op_ptr->results.good_calls++;
+       Ops[TOTAL].results.good_calls++;
+       ret++;
+    } else {
+       if (DEBUG_CHILD_ERROR) {
+            (void) fprintf(stderr, "%s: write call RPC error %d on file %d\n",
+                           sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
+       }
+       op_ptr->results.bad_calls++;
+       Ops[TOTAL].results.bad_calls++;
+    }
+
+    return(ret);
+
+} /* op_commit */
+
+
+#define LAD_RETRIABLE(stat) (((stat) == RPC_TIMEDOUT) || ((stat) == RPC_CANTDECODERES))
+
+/*
+ * Reliably lookup a file in the current directory
+ * Return:
+ *     -1      RPC error
+ *     1       File doesn't exist
+ *     0       File exists
+ */
+int
+lad_lookup(sfs_fh_type *file_ptr, char *name)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_lookup: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+        (void) memmove((char *) &args.what.dir, (char *) &file_ptr->dir->fh3,
+                                                       sizeof (nfs_fh3));
+       args.what.name = name;
+        (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_lookup(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status == NFS3ERR_NOENT) {
+       return(1);
+    }
+
+    if (reply.status != NFS3_OK) {
+       (void) fprintf(stderr, "lad_lookup(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+       return(-1);
+    }
+
+    file_ptr->state = Exists;
+    (void) memmove((char *) &file_ptr->fh3,
+                       (char *) &reply.resok.object,
+                       sizeof (nfs_fh3));
+    (void) strcpy(file_ptr->file_name, name);
+    (void) memmove((char *) &file_ptr->attributes3,
+                               (char *) &reply.resok.obj_attributes.attr,
+                               sizeof (file_ptr->attributes3));
+    file_ptr->size = fh_size(file_ptr);
+    return(0);
+}
+
+/*
+ * Reliably remove a file in the current directory
+ */
+int
+lad_remove(sfs_fh_type *file_ptr, char *name)
+{
+    REMOVE3args         args;
+    REMOVE3res          reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does exist
+     */
+    if (file_ptr->attributes3.type == NF3DIR)
+       return (lad_rmdir(file_ptr, name));
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_remove: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.object.name = name;
+       (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
+                       sizeof(nfs_fh3));
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
+                        xdr_REMOVE3args, (char *) &args,
+                        xdr_REMOVE3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_remove(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_remove(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably remove a directory in the current directory
+ */
+int
+lad_rmdir(sfs_fh_type *file_ptr, char *name)
+{
+    RMDIR3args          args;
+    RMDIR3res           reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does exist and is empty
+     */
+    if (file_ptr->attributes3.type != NF3DIR)
+       return (lad_remove(file_ptr, name));
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_rmdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       args.object.name = name;
+        (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
+                        xdr_RMDIR3args, (char *) &args,
+                        xdr_RMDIR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_rmdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_NOENT || !retried) {
+           (void) fprintf(stderr, "lad_rmdir(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    file_ptr->state = Nonexistent;
+
+    return(0);
+}
+
+/*
+ * Reliably create a symlink in the current directory
+ */
+int
+lad_symlink(sfs_fh_type *file_ptr, char *target, char *name)
+{
+    SYMLINK3args        args;
+    SYMLINK3res         reply;                 /* the reply */
+    char               sym_data[NFS_MAXPATHLEN];       /* symlink data */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_symlink: %lx[%lx] %s -> %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name, target);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+         args.where.name = name;
+
+       (void) strcpy(sym_data, "./");
+       (void) strcat(sym_data, target);
+       args.symlink.symlink_attributes.size.set_it = TRUE;
+       args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
+       args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
+       args.symlink.symlink_data = sym_data;
+
+       args.symlink.symlink_attributes.mode.set_it = TRUE;
+       args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
+       args.symlink.symlink_attributes.uid.set_it = TRUE;
+       args.symlink.symlink_attributes.uid.uid = Cur_uid;
+       args.symlink.symlink_attributes.gid.set_it = TRUE;
+       args.symlink.symlink_attributes.gid.gid = Cur_gid;
+       args.symlink.symlink_attributes.atime.set_it = TRUE;
+       args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
+       args.symlink.symlink_attributes.atime.atime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.symlink.symlink_attributes.mtime.set_it = TRUE;
+       args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.symlink.symlink_attributes.mtime.mtime.nseconds =
+                                                Cur_time.usec * 1000;
+
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
+                        xdr_SYMLINK3args, (char *) &args,
+                        xdr_SYMLINK3res, (char *) &reply,
+                       Nfs_timers[Init]);
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_symlink(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_symlink(%s, %s) NFS call failed : %s\n",
+                       target, name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+    }
+
+    /*
+     * SYMLINK may not return a fh. If we try to
+     * access this symlink (eg, remove(), readlink())
+     * before we do a lookup, we won't have a fh to use.
+     * So, we do a lookup call here.
+     * If it fails, we fill in what we can.
+     */  
+    return (lad_lookup(file_ptr, name));
+}
+
+/*
+ * Reliably create a directory in the current directory
+ */
+int
+lad_mkdir(sfs_fh_type *file_ptr, char *name)
+{
+    MKDIR3args          args;
+    MKDIR3res           reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_mkdir: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+       args.where.name = name;
+       args.attributes.mode.set_it = TRUE;
+       args.attributes.mode.mode = (NFSMODE_DIR | 0777);
+       args.attributes.uid.set_it = TRUE;
+       args.attributes.uid.uid = Cur_uid;
+       args.attributes.gid.set_it = TRUE;
+       args.attributes.gid.gid = Cur_gid;
+       args.attributes.size.set_it = TRUE;
+       args.attributes.size.size._p._u = 0;
+       args.attributes.size.size._p._l = 512;
+       args.attributes.atime.set_it = TRUE;
+       args.attributes.atime.atime.seconds = Cur_time.esec;
+       args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+       args.attributes.mtime.set_it = TRUE;
+       args.attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
+                        xdr_MKDIR3args, (char *) &args,
+                        xdr_MKDIR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_mkdir(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFS3ERR_EXIST)
+       return(1);
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_mkdir(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+       /*
+        * If the first mkdir suceeded but the reply as dropped and
+        * was retransmitted, we still need to lookup the attributes
+        */
+       if (lad_lookup(file_ptr, name))
+          return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh3,
+                   (char *) &reply.resok.obj.handle,
+                   sizeof (nfs_fh3));
+       (void) strcpy(file_ptr->file_name, name);
+       (void) memmove((char *) &file_ptr->attributes3,
+                   (char *) &reply.resok.obj_attributes.attr,
+                   sizeof(file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+    }
+    file_ptr->state = Empty_dir;
+
+    return(0);
+}
+
+/*
+ * Reliably commit a file
+ */
+static int
+lad_commit(sfs_fh_type *file_ptr)
+{
+    COMMIT3args                        args;
+    COMMIT3res                 reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_commit: %lx[%lx]\n",
+                       sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir);
+       (void) fflush(stderr);
+    }
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
+               sizeof (nfs_fh3));
+    args.offset._p._u = args.offset._p._l = (uint32_t) 0;
+    args.count = file_ptr->attributes3.size._p._l;
+
+    /* CONSTCOND */
+    while (1) {
+        rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
+                               xdr_COMMIT3args, (char *) &args,
+                               xdr_COMMIT3res, (char *) &reply,
+                               Nfs_timers[Init]);
+        if (rpc_stat == RPC_SUCCESS) 
+           break;
+        if (rpc_stat != RPC_TIMEDOUT) {
+           (void) fprintf(stderr, "lad_commit() RPC call failed : %s\n",
+                               clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    return(0);
+}
+
+/*
+ * Reliably write a file in the current directory
+ */
+int
+lad_write(sfs_fh_type *file_ptr, int32_t offset, int32_t length)
+{
+    static char                        *buf = NULL;    /* the data buffer */
+    int32_t                    size;           /* size of data write */
+    int32_t                    cur_cnt;
+    WRITE3args                  args;
+    WRITE3res                   reply;          /* the reply */
+    enum clnt_stat             rpc_stat;       /* result from RPC call */
+    int                                async = 1;
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_write: %lx[%lx] %ld %ld\n",
+                       sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, offset, length);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * This function presumes that the file name does exist
+     * Initialize write buffer to known value
+     */
+    if (buf == NULL) {
+       buf = init_write_buffer();
+    }
+
+    /*
+     * If a short file write don't bother with the commit, just write sync.
+     */
+    if (length <= Bytes_per_block)
+       async = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
+                sizeof (nfs_fh3));
+    args.offset._p._u = 0;
+    args.offset._p._l = offset;
+    if (async)
+           args.stable = UNSTABLE;
+    else
+           args.stable = FILE_SYNC;
+
+    size = Bytes_per_block;
+    for (cur_cnt = 0; cur_cnt < length; cur_cnt += size) {
+       if ((cur_cnt + size) > length)
+               size = length - cur_cnt;
+
+       if (size == 0)
+           break;
+
+       args.count = size;
+       args.data.data_len = size;
+       args.data.data_val = buf;
+
+       /* make the call now */
+        /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
+                                xdr_WRITE3args, (char *) &args,
+                                xdr_WRITE3res, (char *) &reply,
+                               Nfs_timers[Init]);
+
+           if (rpc_stat == RPC_SUCCESS) 
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_write() RPC call failed : %s\n",
+                               clnt_sperrno(rpc_stat));
+           }
+           if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+           }
+       }
+       if (reply.status != NFS3_OK) {
+           (void) fprintf(stderr, "lad_write() NFS call failed : %s\n",
+                       nfs3_strerror(reply.status));
+           return(-1);
+       }
+       file_ptr->state = Exists;
+        (void) memmove((char *) &file_ptr->attributes3,
+                                (char *) &reply.resok.file_wcc.after.attr,
+                                sizeof (file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+
+        args.offset._p._l += size;
+    }
+
+    if (async)
+       (void) lad_commit(file_ptr);
+    return(0);
+}
+
+/*
+ * Reliably create a file in the current directory
+ */
+int
+lad_create(sfs_fh_type *file_ptr, char *name)
+{
+    CREATE3args         args;
+    CREATE3res          reply;                  /* the reply */
+    enum clnt_stat     rpc_stat;               /* result from RPC call */
+    int                        retried = 0;
+
+    /*
+     * This function presumes that the file name does not already exist
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_create: %lx[%lx] %s\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /* set up the arguments */
+       (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
+                sizeof (nfs_fh3));
+       args.where.name = name;
+       args.how.mode = UNCHECKED;
+       args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
+       args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+       args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+       args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.atime.atime.seconds =
+                                               Cur_time.esec;
+       args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.mtime.mtime.seconds =
+                                               Cur_time.esec;
+       args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                                Cur_time.usec * 1000;
+       args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+       args.how.createhow3_u.obj_attributes.size.size._p._u =
+                                               (uint32_t) 0;
+       args.how.createhow3_u.obj_attributes.size.size._p._l =
+                                               (uint32_t) 0;
+
+       /* make the call now */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
+                        xdr_CREATE3args, (char *) &args,
+                        xdr_CREATE3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void) fprintf(stderr, "lad_create(%s) RPC call failed : %s\n",
+                               name, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+       retried++;
+    }
+
+    if (!retried && reply.status == NFS3ERR_EXIST) {
+       return(1);
+    }
+
+    if (reply.status != NFS3_OK) {
+       if (reply.status != NFS3ERR_EXIST || !retried) {
+           (void) fprintf(stderr, "lad_create(%s) NFS call failed : %s\n",
+                       name, nfs3_strerror(reply.status));
+           return(-1);
+       }
+        /*
+         * If the first create suceeded but the reply as dropped and
+         * was retransmitted, we still need to lookup the attributes
+         */
+        if (lad_lookup(file_ptr, name))
+           return (-1);
+    } else {
+       (void) memmove((char *) &file_ptr->fh3,
+                   (char *) &reply.resok.obj.handle,
+                   sizeof (nfs_fh3));
+       (void) strcpy(file_ptr->file_name, name);
+       (void) memmove((char *) &file_ptr->attributes3,
+                   (char *) &reply.resok.obj_attributes.attr,
+                   sizeof(file_ptr->attributes3));
+       file_ptr->size = fh_size(file_ptr);
+    }
+
+    file_ptr->state = Exists;
+    /*
+     * Directories are created as Empty_dir, when a file is created it
+     * becomes an Exists.
+     */
+    file_ptr->dir->state = Exists;
+
+    return(0);
+}
+
+/*
+ * Reliably set the size of a file in the current directory
+ */
+int
+lad_truncate(sfs_fh_type *file_ptr, int32_t size)
+{
+    SETATTR3args        args;
+    SETATTR3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+
+    /*
+     * This function presumes that the file name already exists
+     */
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "%s:lad_truncate: %lx[%lx] %ld\n", sfs_Myname,
+                       (int32_t) file_ptr, (int32_t) file_ptr->dir, size);
+       (void) fflush(stderr);
+    }
+
+    /* CONSTCOND */
+    while (1) {
+       /*
+        * set up the arguments
+        * Set the mode and times as well
+        */
+       (void) memmove((char *) &args.object, (char *) &file_ptr->fh3,
+                                                        sizeof (nfs_fh3));
+       args.new_attributes.mode.set_it = TRUE;
+       args.new_attributes.mode.mode = (uint32_t) 0666;
+       args.new_attributes.uid.set_it = FALSE;
+       args.new_attributes.uid.uid = (uint32_t) -1;
+       args.new_attributes.gid.set_it = FALSE;
+       args.new_attributes.gid.gid = (uint32_t) -1;
+       args.new_attributes.size.set_it = TRUE;
+       args.new_attributes.size.size._p._u = 0;
+       args.new_attributes.size.size._p._l = size;
+       args.new_attributes.atime.set_it = TRUE;
+       args.new_attributes.atime.atime.seconds = Cur_time.esec;
+       args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+       args.new_attributes.mtime.set_it = TRUE;
+       args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
+       args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+       args.guard.check = FALSE;
+
+       /* make the call */
+       rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
+                        xdr_SETATTR3args, (char *) &args,
+                        xdr_SETATTR3res, (char *) &reply,
+                       Nfs_timers[Init]);
+
+       if (rpc_stat == RPC_SUCCESS) 
+               break;
+       if (rpc_stat != RPC_TIMEDOUT) {
+               (void)fprintf(stderr,
+                               "lad_truncate(%ld) RPC call failed : %s\n",
+                               size, clnt_sperrno(rpc_stat));
+       }
+       if (!LAD_RETRIABLE(rpc_stat)) {
+               return(-1);
+       }
+    }
+
+    if (reply.status != NFS3_OK) {
+       (void) fprintf(stderr, "lad_truncate(%ld) NFS call failed : %s\n",
+                       size, nfs3_strerror(reply.status));
+       return(-1);
+    }
+    (void) memmove(&file_ptr->attributes3,
+                   &reply.resok.obj_wcc.after.attr,
+                   sizeof (file_ptr->attributes3));
+    file_ptr->size = fh_size(file_ptr);
+
+    return(0);
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/* sfs_3_ops.c */
diff --git a/TBBT/trace_play/sfs_3_vld.c b/TBBT/trace_play/sfs_3_vld.c
new file mode 100644 (file)
index 0000000..8ede891
--- /dev/null
@@ -0,0 +1,2126 @@
+#ifndef lint
+static char sfs_3_vldSid[] = "@(#)sfs_3_vld.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *      Copyright 1991,1992  Legato Systems, Inc.                *
+ *      Copyright 1991,1992  Auspex Systems, Inc.                *
+ *      Copyright 1991,1992  Data General Corporation            *
+ *      Copyright 1991,1992  Digital Equipment Corporation       *
+ *      Copyright 1991,1992  Interphase Corporation              *
+ *      Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ------------------------------ sfs_3_vld.c ---------------------------
+ *
+ * Validation suite for sfs.
+ *
+ *.Exported_routines
+ *      void Validate_ops(int, char **)
+ *
+ *.Local_routines
+ *      void validate_init_rpc()
+ *      void validate_creation(void)
+ *      void validate_attributes(void)
+ *      void validate_read_write(void)
+ *      void validate_rename(void)
+ *      int compare_sattr(char *, char *, sattr3 *, fattr3 *)
+ *      int compare_fattr(char *, char *, fattr3 *, fattr3 *)
+ *      uint16_t sum(unsigned char *, int)
+ *      void validate_remove(void)
+ *      void validate_cleanup(void)
+ *      void validate_exit(void)
+ *      void verror(int, ValMsgType, char *, ...)
+ *
+ *.Revision History
+ *     11-Jul-94       ChakChung Ng    Created
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sfs_c_def.h"
+
+extern struct hostent   *Server_hostent;
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+
+/* forward definitions for local routines */
+/*
+ * validate options
+ * BATCH       - do complete pass of validation, reporting errors if any
+ * VERBOSE     - prints step-by-step validation actions being performed
+ * INTERACTIVE - VERBOSE and if any errors encountered, ask to continue
+ *               validation or not.
+ */
+#define        VAL_BATCH       1
+#define VAL_VERBOSE    2
+#define        VAL_INTERACTIVE 3
+
+typedef enum {
+       I = 1,
+       W = 2,
+       E = 3
+} ValMsgType;
+
+#define NUMREGFILES    21
+#define NUMDIRS                10
+#define NUMLINKS       10
+#define NUMSYMLINKS    10
+#define NUMFILES       NUMREGFILES + NUMDIRS + NUMLINKS + NUMSYMLINKS
+#define NUMFRAGS       8
+
+static void val_op_null(void);
+static void val_op_getattr(GETATTR3args *, GETATTR3res *);
+static void val_op_setattr(SETATTR3args *, SETATTR3res *);
+static void val_op_lookup(LOOKUP3args *, LOOKUP3res *);
+static void val_op_access(ACCESS3args *, ACCESS3res *);
+static void val_op_readlink(READLINK3args *, READLINK3res *);
+static void val_op_read(READ3args *, READ3res *);
+static void val_op_write(WRITE3args *, WRITE3res *);
+static void val_op_create(CREATE3args *, CREATE3res *);
+static void val_op_mkdir(MKDIR3args *, MKDIR3res *);
+static void val_op_symlink(SYMLINK3args *, SYMLINK3res *);
+static void val_op_mknod(MKNOD3args *, MKNOD3res *);
+static void val_op_remove(REMOVE3args *, REMOVE3res *);
+static void val_op_rmdir(RMDIR3args *, RMDIR3res *);
+static void val_op_rename(RENAME3args *, RENAME3res *);
+static void val_op_link(LINK3args *, LINK3res *);
+static void val_op_readdir(READDIR3args *, READDIR3res *);
+static void val_op_readdirplus(READDIRPLUS3args *, READDIRPLUS3res *);
+static void val_op_fsstat(FSSTAT3args *, FSSTAT3res *);
+static void val_op_fsinfo(FSINFO3args *, FSINFO3res *);
+static void val_op_pathconf(PATHCONF3args *, PATHCONF3res *);
+static void val_op_commit(COMMIT3args *, COMMIT3res *);
+
+static void validate_init_rpc(void);
+static void validate_exit(void);
+static void validate_creation(void);
+static void validate_attributes(void);
+static void validate_read_write(void);
+static void validate_rename(void);
+static void validate_remove(void);
+static void validate_cleanup(void);
+static int compare_sattr(char *, char *, sattr3 *, fattr3 *);
+static int compare_fattr(char *, char *, fattr3 *, fattr3 *);
+static uint16_t sum(unsigned char *, int);
+static void verror(int, ValMsgType, char *, ...);
+static void create_3tmp_handles(void);
+static void delete_3tmp_handles(void);
+
+/*
+ * ----------------------  Static Declarations ----------------------
+ */
+
+int Validate;
+
+static int Validate_errors = 0;
+static char Testdirname[SFS_MAXPATHLEN];    /* test dir component name */
+/*
+ * packed structure to keep track of file status
+ */
+struct sfs_fileinfo {
+    int file_found:1,   /* file has been found */
+        file_is_dup:1,  /* file has a duplicate */
+        pad:30;         /* pad the rest */
+};
+
+typedef struct sfs_fileinfo sfs_fileinfo;
+/*
+ * This vector is used for readdirplus validation currently, but could be
+ * extended to keep track of other interesting pieces of information.
+ */
+static sfs_fileinfo check_files[NUMFILES];
+
+/*
+ * ----------------------  SFS Validation Suite  ----------------------
+ */
+
+/*
+ * XXXXX Must make sure that we validate that all servers return back
+ * XXXXX All optional values
+ */
+void
+Validate_ops(
+    int         argc,
+    char *      argv[])
+{
+    char *      valdir;
+    CLIENT *    mount_client_ptr;
+    int i;
+
+    if (argc > 1) {
+       verror(VAL_BATCH, E, "Can only validate one directory at a time.\n");
+       exit(1);
+    }
+
+    Num_io_files = NUMFILES;
+    Cur_uid = Real_uid;
+    nfs_version = NFS_V3;
+
+    if (argc == 0)
+       valdir = ".";
+    else
+       valdir = argv++[0];
+
+    (void) sprintf(Testdirname, "%s/validatedir", valdir);
+
+    do {
+       verror(VAL_BATCH, I, "validating sfs on \"%s\" directory ...\n",
+               valdir);
+
+       init_fileinfo();
+       create_3tmp_handles();
+
+       /*
+        * need priv port to do following
+        */
+       mount_client_ptr = lad_getmnt_hand(valdir);
+       if (mount_client_ptr == NULL) {
+           exit(1);
+       }
+       validate_init_rpc();
+
+       /*
+        * should be all done doing priv port stuff
+        */
+       if (setuid(Real_uid) != 0) {
+          (void) fprintf(stderr,"%s: %s%s\n",
+                  sfs_Myname, "cannot perform setuid operation.\n",
+                  "Do `make install` as root.\n");
+       }
+
+       init_mount_point(0, valdir, mount_client_ptr);
+
+        /*
+         * initialize the check_file array
+         */
+        (void) memset((void *) check_files, '\0', sizeof(check_files));
+
+       verror(VAL_VERBOSE, I, "validating null operation ...\n");
+       val_op_null();
+
+       validate_creation();
+       validate_attributes();
+       validate_read_write();
+       validate_rename();
+       validate_remove();
+       argc--;
+       valdir = argv++[0];
+
+       /*
+        * Cleanup mount client handle
+        */
+       clnt_destroy(mount_client_ptr);
+
+       delete_3tmp_handles();
+       validate_cleanup();
+    } while (argc > 0);
+
+    validate_exit();
+
+} /* Validate_ops */
+
+
+/*
+ * allocate and initialize client handles
+ */
+static void
+validate_init_rpc(void)
+{
+       NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                        (uint32_t) NFS_PROGRAM,
+                                        (uint32_t) NFS_V3,
+                                        RPC_ANYSOCK, &Nfs_timers[0]);
+
+       if (NFS_client == ((CLIENT *) NULL)) { 
+                   verror(VAL_BATCH, E,
+                               "portmap/nfsd server not responding\n"); 
+                   exit(1); 
+       }
+       NFS_client->cl_auth = authunix_create(lad_hostname, Real_uid,
+                                      Cur_gid, 0, NULL);
+} /* validate_init_rpc */
+
+
+static void
+validate_creation(void)
+{
+    int                 filenum;
+    int                 target_filenum;
+    CREATE3args                argcr;
+    CREATE3res         repcr;
+    MKDIR3args         argmk;
+    MKDIR3res          repmk;
+    LINK3args          argln;
+    LINK3res           repln;
+    SYMLINK3args       argsl;
+    SYMLINK3res                repsl;
+    LOOKUP3args                arglp;
+    LOOKUP3res         replp;
+    READLINK3args      argrl;
+    READLINK3res       reprl;
+    char                sl_target_path[NFS_MAXPATHLEN];
+    char                sym_data[NFS_MAXPATHLEN];
+
+    for (filenum=0; filenum < NUMFILES ; filenum++) {
+
+       Cur_file_ptr = &Io_files[filenum];
+       sfs_gettime(&Cur_time);
+
+       if (filenum < NUMREGFILES) {
+
+           (void) sprintf(Cur_filename, Filespec, filenum);
+
+           /* regular file creation */
+           (void) memmove((char *) &argcr.where.dir, (char *) &Export_dir.fh3,
+                               sizeof (nfs_fh3));
+           argcr.where.name = Cur_filename;
+           argcr.how.mode = UNCHECKED;
+           argcr.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.mode.mode =
+                                                       (NFSMODE_REG | 0666);
+           argcr.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
+           argcr.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
+           argcr.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+           argcr.how.createhow3_u.obj_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+           argcr.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.mtime.mtime.seconds =
+                                                       Cur_time.esec;
+           argcr.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+           argcr.how.createhow3_u.obj_attributes.size.set_it = TRUE;
+           argcr.how.createhow3_u.obj_attributes.size.size._p._u =
+                                                       (uint32_t) 0;
+           argcr.how.createhow3_u.obj_attributes.size.size._p._l =
+                                                       (uint32_t) 0;
+
+           (void) memset((char *) &repcr.resok.obj.handle, '\0',
+                                                       sizeof (nfs_fh3));
+           verror(VAL_VERBOSE, I, "validating create file %s ...\n",
+                   Cur_filename);
+           val_op_create(&argcr, &repcr);
+
+           if (repcr.status == NFS3_OK) {
+               Cur_file_ptr->state = Exists;
+               (void) memmove((char *) &Cur_file_ptr->fh3,
+                               (char *) &repcr.resok.obj.handle,
+                               sizeof (nfs_fh3));
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &repcr.resok.obj_attributes.attr,
+                               sizeof(Cur_file_ptr->attributes3));
+               (void) compare_sattr(Ops[CREATE].name, Io_files[filenum].file_name,
+                                       &argcr.how.createhow3_u.obj_attributes,
+                                       &Cur_file_ptr->attributes3);
+           } else {
+               Cur_file_ptr->state = Nonexistent;
+               errno = (int)repcr.status;
+               verror(VAL_BATCH, E, "create %s failed: %m\n",
+                         Cur_filename);
+               /*
+                * An error in file creation is fatal, because we use the
+                * created files to validate the other operations.
+                */
+               validate_exit();
+           }
+
+       } else if (filenum < NUMREGFILES + NUMDIRS) {
+
+           (void) sprintf(Cur_filename, Dirspec, filenum - NUMREGFILES);
+
+           /* directory creation */
+           (void) memmove((char *) &argmk.where.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+           argmk.where.name = Cur_filename;
+           argmk.attributes.mode.set_it = TRUE;
+           argmk.attributes.mode.mode = (NFSMODE_DIR | 0777);
+           argmk.attributes.uid.set_it = TRUE;
+           argmk.attributes.uid.uid = Cur_uid;
+           argmk.attributes.gid.set_it = TRUE;
+           argmk.attributes.gid.gid = Cur_gid;
+           argmk.attributes.size.set_it = FALSE;
+           argmk.attributes.size.size._p._u = (uint32_t) 0;
+           argmk.attributes.size.size._p._l = (uint32_t) 0;
+           argmk.attributes.atime.set_it = TRUE;
+           argmk.attributes.atime.atime.seconds = Cur_time.esec;
+           argmk.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+           argmk.attributes.mtime.set_it = TRUE;
+           argmk.attributes.mtime.mtime.seconds = Cur_time.esec;
+           argmk.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+
+           (void) memset((char *) &repmk.resok.obj.handle, '\0', sizeof (nfs_fh3));
+           verror(VAL_VERBOSE, I, "validating mkdir %s ...\n", Cur_filename);
+           val_op_mkdir(&argmk, &repmk);
+
+           if (repmk.status == NFS3_OK) {
+               Cur_file_ptr->state = Exists;
+               (void) memmove((char *) &Cur_file_ptr->fh3,
+                               (char *) &repmk.resok.obj.handle,
+                               sizeof (nfs_fh3));
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &repmk.resok.obj_attributes.attr,
+                               sizeof(Cur_file_ptr->attributes3));
+               (void) compare_sattr(Ops[MKDIR].name, Io_files[filenum].file_name,
+                               &argmk.attributes, &Cur_file_ptr->attributes3);
+           } else {
+               Cur_file_ptr->state = Nonexistent;
+               verror(VAL_BATCH, W, "mkdir %s failed:%m\n", Cur_filename);
+           }
+
+       } else if (filenum < NUMREGFILES + NUMDIRS + NUMLINKS ) {
+
+           (void) sprintf(Cur_filename, Filespec, filenum - NUMDIRS);
+
+           /* hard link creation */
+           target_filenum = NUMFILES-NUMSYMLINKS-1-filenum;
+           (void) memmove((char *) &argln.file,
+                       (char *) &Io_files[target_filenum].fh3,
+                       sizeof (nfs_fh3));
+           (void) memmove((char *) &argln.link.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+           argln.link.name = Cur_filename;
+
+           verror(VAL_VERBOSE, I, "validating link %s %s ...\n",
+                   Io_files[target_filenum].file_name, Cur_filename);
+           val_op_link(&argln, &repln);
+
+           if (repln.status == NFS3_OK) {
+               Cur_file_ptr->state = Exists;
+               (void) memmove((char *) &Cur_file_ptr->fh3,
+                               (char *) &Io_files[target_filenum].fh3,
+                               sizeof (nfs_fh3));
+               (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+               Cur_file_ptr->attributes3 = Io_files[target_filenum].attributes3;
+               Io_files[target_filenum].attributes3.nlink++;
+               Cur_file_ptr->attributes3.nlink++;
+           } else {
+               Cur_file_ptr->state = Nonexistent;
+               verror(VAL_BATCH, W, "link %s failed: %m\n", Cur_filename);
+               exit(1);
+           }
+
+       } else {
+
+           (void) sprintf(Cur_filename, Symspec, filenum -
+                                       (NUMREGFILES + NUMDIRS + NUMLINKS));
+
+           /* symbolic link creation */
+           target_filenum = NUMFILES-1-filenum;
+           (void) memmove((char *) &argsl.where.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+           argsl.where.name = Cur_filename;
+           (void) sprintf(sl_target_path,
+                          "./%s", Io_files[target_filenum].file_name);
+           argsl.symlink.symlink_attributes.size.set_it = TRUE;
+           argsl.symlink.symlink_attributes.size.size._p._u =
+                                       (uint32_t) 0;
+           argsl.symlink.symlink_attributes.size.size._p._l =
+                                       (uint32_t) strlen(sl_target_path);
+           argsl.symlink.symlink_data = sl_target_path;
+           argsl.symlink.symlink_attributes.mode.set_it = TRUE;
+           argsl.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
+           argsl.symlink.symlink_attributes.uid.set_it = TRUE;
+           argsl.symlink.symlink_attributes.uid.uid = Cur_uid;
+           argsl.symlink.symlink_attributes.gid.set_it = TRUE;
+           argsl.symlink.symlink_attributes.gid.gid = Cur_gid;
+           argsl.symlink.symlink_attributes.atime.set_it = TRUE;
+           argsl.symlink.symlink_attributes.atime.atime.seconds =
+                                                       Cur_time.esec;
+           argsl.symlink.symlink_attributes.atime.atime.nseconds =
+                                                       Cur_time.usec * 1000;
+           argsl.symlink.symlink_attributes.mtime.set_it = TRUE;
+           argsl.symlink.symlink_attributes.mtime.mtime.seconds =
+                                                       Cur_time.esec;
+           argsl.symlink.symlink_attributes.mtime.mtime.nseconds =
+                                                       Cur_time.usec * 1000;
+
+           verror(VAL_VERBOSE, I, "validating symlink %s %s ...\n",
+                   sl_target_path, Cur_filename);
+           val_op_symlink(&argsl, &repsl);
+
+           if (repsl.status == NFS3_OK) {
+               Cur_file_ptr->state = Exists;
+
+               /* do a lookup to get file handle and attributes */
+               (void) memmove((char *) &arglp.what.dir, (char *) &Export_dir.fh3,
+                               sizeof (nfs_fh3));
+               arglp.what.name = Cur_filename;
+               (void) memset((char *) &replp.resok.object, '\0', sizeof (nfs_fh3));
+
+               val_op_lookup(&arglp, &replp);
+
+               if (replp.status == NFS3_OK) {
+                   (void) memmove((char *) &Cur_file_ptr->fh3,
+                               (char *) &replp.resok.object,
+                               sizeof (nfs_fh3));
+                   (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
+                   (void) memmove((char *) &Cur_file_ptr->attributes3,
+                               (char *) &replp.resok.obj_attributes.attr,
+                               sizeof (Cur_file_ptr->attributes3));
+                   (void) compare_sattr(Ops[SYMLINK].name,
+                                       Io_files[filenum].file_name,
+                                       &argsl.symlink.symlink_attributes,
+                                       &Cur_file_ptr->attributes3);
+               } else {
+                   verror(VAL_BATCH, W, "lookup %s failed: %m\n",
+                           Cur_filename);
+                   continue;
+               }
+
+               /* validate readlink */
+               (void) memmove((char *) &argrl.symlink,
+                               (char *) &Cur_file_ptr->fh3,
+                               sizeof (nfs_fh3));
+               reprl.resok.data = sym_data;
+
+               verror(VAL_VERBOSE, I, "validating readlink %s ...\n",
+                       Cur_filename);
+               val_op_readlink(&argrl, &reprl);
+
+               if (reprl.status == NFS3_OK) {
+                   if (strcmp(sl_target_path, sym_data)) {
+                       verror(VAL_BATCH, W,
+                           "readlink %s error, result = %s, should be %s\n",
+                           Cur_filename, reprl.resok.data,
+                           sl_target_path);
+                   }
+               } else {
+                   verror(VAL_BATCH, W, "readlink %s failed:%m\n",
+                           Cur_filename);
+               }
+
+           } else {
+               Cur_file_ptr->state = Nonexistent;
+               verror(VAL_BATCH, W, "symlink %s failed: %m\n", Cur_filename);
+           }
+       }
+    } /* end for each file */
+
+} /* validate_creation */
+
+
+static void
+validate_attributes(void)
+{
+    int                 filenum;
+    LOOKUP3args                arglp;
+    LOOKUP3res         replp;
+    GETATTR3args       argga;
+    GETATTR3res                repga;
+    SETATTR3args       argsa;
+    SETATTR3res                repsa;
+
+    /* validate fsstat */
+
+    /* validate lookup */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+       (void) memmove((char *) &arglp.what.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+       arglp.what.name = Io_files[filenum].file_name;
+       (void) memset((char *) &replp.resok.object, '\0', sizeof (nfs_fh3));
+
+       verror(VAL_VERBOSE, I, "validating lookup %s ...\n",
+               Io_files[filenum].file_name);
+       val_op_lookup(&arglp, &replp);
+
+       if (replp.status == NFS3_OK) {
+           if (memcmp((char *) &(Io_files[filenum].fh3),
+                    (char *) &(replp.resok.object), sizeof (nfs_fh3))) {
+               verror(VAL_BATCH, W, "lookup %s: file handle mismatch\n",
+                               Io_files[filenum].file_name);
+               exit(1);
+           }
+           (void) compare_fattr(Ops[LOOKUP].name, Io_files[filenum].file_name,
+                                       &Io_files[filenum].attributes3,
+                                       &replp.resok.obj_attributes.attr);
+       } else {
+           verror(VAL_BATCH, W, "lookup %s failed:%m\n",
+                   Io_files[filenum].file_name);
+       }
+    }
+
+    /* validate getattr */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+       (void) memmove((char *) &argga.object,
+                       (char *) &Io_files[filenum].fh3,
+                       sizeof (nfs_fh3));
+
+       verror(VAL_VERBOSE, I, "validating getattr %s ...\n",
+               Io_files[filenum].file_name);
+       val_op_getattr(&argga, &repga);
+
+       if (repga.status == NFS3_OK) {
+           (void) compare_fattr(Ops[GETATTR].name, Io_files[filenum].file_name,
+                         &Io_files[filenum].attributes3,
+                         &repga.resok.obj_attributes);
+       } else {
+           verror(VAL_BATCH, W, "getattr %s failed: %m\n",
+                   Io_files[filenum].file_name);
+       }
+    }
+
+    /*validate setattr */
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+       sfs_gettime(&Cur_time);
+       (void) memmove((char *) &argsa.object,
+                       (char *) &Io_files[filenum].fh3,
+                       sizeof (nfs_fh3));
+       argsa.new_attributes.mode.set_it = TRUE;
+       if (filenum >= NUMREGFILES && filenum < NUMREGFILES + NUMDIRS)
+         argsa.new_attributes.mode.mode = 0777;
+       else
+         argsa.new_attributes.mode.mode = 0666;
+       argsa.new_attributes.uid.set_it = FALSE;
+       argsa.new_attributes.uid.uid = 0;
+       argsa.new_attributes.gid.set_it = FALSE;
+       argsa.new_attributes.gid.gid = 0;
+       argsa.new_attributes.size.set_it = FALSE;
+       argsa.new_attributes.size.size._p._u = 0;
+       argsa.new_attributes.size.size._p._l = 0;
+       argsa.new_attributes.atime.set_it = TRUE;
+       argsa.new_attributes.atime.atime.seconds = Cur_time.esec;
+       argsa.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
+       argsa.new_attributes.mtime.set_it = TRUE;
+       argsa.new_attributes.mtime.mtime.seconds = Cur_time.esec;
+       argsa.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
+       argsa.guard.check = FALSE;
+
+       verror(VAL_VERBOSE, I, "validating setattr %s ...\n",
+                               Io_files[filenum].file_name);
+       val_op_setattr(&argsa, &repsa);
+
+       if (repsa.status == NFS3_OK) {
+           (void) memmove((char *) &Io_files[filenum].attributes3,
+                               (char *) &repsa.resok.obj_wcc.after.attr,
+                               sizeof (Io_files[filenum].attributes3));
+           (void) compare_sattr(Ops[SETATTR].name, Io_files[filenum].file_name,
+                       &argsa.new_attributes, &repsa.resok.obj_wcc.after.attr);
+
+           (void) memmove((char *) &argga.object,
+                               (char *) &Io_files[filenum].fh3,
+                               sizeof (nfs_fh3));
+
+           val_op_getattr(&argga, &repga);
+
+           if (repga.status == NFS3_OK) {
+               (void) compare_fattr(Ops[GETATTR].name, Io_files[filenum].file_name,
+                                               &Io_files[filenum].attributes3,
+                                               &repga.resok.obj_attributes);
+           } else {
+               verror(VAL_BATCH, W, "getattr %s failed: %m\n",
+                       Io_files[filenum].file_name);
+           }
+       } else {
+           verror(VAL_BATCH, W, "setattr %s failed: %m\n",
+                   Io_files[filenum].file_name);
+           exit(1);
+       }
+    }
+
+} /* validate_attributes */
+
+#define WAITFOREOF 1
+/*
+ * need to check if readdirplus returns a reasonable amount of data.
+ */
+static void
+val_rddirplus_retsize(uint32_t dircount, uint32_t maxcount,
+                      READDIRPLUS3resok *rp)
+{
+    entryplus3 *esp;
+    static int eof_wait = 0;
+    int i;
+    int size = 0;
+    int tsize = 0;
+    int msize = 0;
+    double mpcnt = 0;
+
+    esp = rp->reply.entries;
+
+    for (i = 0; i < rp->count; i++) {
+            size += sizeof(esp[i].fileid);
+            size += strlen(esp[i].name) * sizeof(char);
+            size += sizeof(esp[i].cookie);
+            tsize += sizeof(esp[i].name_attributes);
+            tsize += sizeof(esp[i].name_handle.handle_follows);
+            tsize += esp[i].name_handle.handle.fh3_length * sizeof(char);
+    }
+
+    msize = size + tsize;
+    mpcnt = (double) msize / (double) maxcount * 100;
+
+    if (rp->reply.eof) {
+        verror(VAL_VERBOSE, I, "readdirplus on %s returned EOF.\n"
+    "\treceived %d bytes of directory information and %d bytes including\n"
+    "\tpost op attributes and filehandle.\n",
+               Testdirname, size, msize);
+    } else if (mpcnt < 80) {
+       eof_wait++;
+        if (eof_wait > WAITFOREOF) {
+            verror(VAL_BATCH, E,
+    "readdirplus on %s did not return a reasonable amount of data.\n"
+    "\treceived %d bytes. should receive close to %d bytes.\n",
+                  Testdirname, msize, maxcount);
+       } else {
+           verror(VAL_VERBOSE, I, "readdirplus on %s did not return EOF.\n"
+    "\treceived %d bytes of directory information and %d bytes including\n"
+    "\tpost op attributes and filehandle.\n",
+                  Testdirname, size, msize);
+       }
+    } else {
+        verror(VAL_VERBOSE, I, "readdirplus on %s did not return EOF.\n"
+    "\treceived %d bytes of directory information and %d bytes including\n"
+    "\tpost op attributes and filehandle.\n",
+               Testdirname, size, msize);
+    }    
+}
+
+static void
+validate_read_write(void)
+{
+    struct {
+       uint16_t  sum;                    /* checksum of data */
+       uint16_t  len;                    /* length of len and data */
+       char            data[DEFAULT_MAX_BUFSIZE - 2 * sizeof(uint16_t)];
+    } block;
+    WRITE3args         argwr;
+    WRITE3res          repwr;
+    READ3args          argrd;
+    READ3res           reprd;
+    READDIR3args       argdr;
+    READDIR3res                repdr;
+    READDIRPLUS3args    argdrp;
+    READDIRPLUS3res     repdrp;
+    int                 maxblks;
+    int                 maxfiles;
+    int                 i;
+    int                 numfiles;
+    int                 filenum;
+    int                 blocknum;
+    entry3              entry_stream[SFS_MAXDIRENTS];
+    entryplus3          entryplus_stream[SFS_MAXDIRENTS];
+
+    /* validate write */
+
+    /* get the maximum number of blocks sfs will write */
+    maxblks = Io_dist_ptr->max_bufs;
+    maxfiles = maxblks > NUMREGFILES ? NUMREGFILES : maxblks;
+
+    /* write maxblks - filenum + 1 blocks to each regular file */
+    argwr.offset._p._u = argwr.offset._p._l = (uint32_t) 0;
+    argwr.stable = FILE_SYNC;
+    argwr.data.data_val = (char *)&block;
+
+    for (blocknum = 0; blocknum <= maxblks ; blocknum++) {
+
+       for (i=0; i < sizeof(block.data); i++)
+           block.data[i] = (char)blocknum;
+
+       for (filenum=0; filenum < maxfiles; filenum++) {
+           /* Write fewer blocks to files with higher numbers. */
+           if (blocknum > (maxblks - filenum))
+               break;
+
+           /* set the length field */
+           if (blocknum == (maxblks - filenum)) {
+               block.len = ((maxfiles - filenum) *
+                       (Bytes_per_block/Kb_per_block)) - (sizeof(block.len) + 
+                                                          sizeof(block.sum));
+               /*
+                 * XXX - write kludge.
+                 *
+                 * Writes must be less than 8K in
+                 * size or else the checksum will incur a buffer overflow
+                 */
+                block.len = (block.len % DEFAULT_MAX_BUFSIZE) -
+                        (sizeof(block.len) + sizeof(block.sum));
+           } else {
+               block.len = Bytes_per_block - (sizeof(block.len)
+                           + sizeof(block.sum));
+           }
+           block.sum = sum((unsigned char *) &block.len,
+                           (int)(block.len + sizeof(block.len)));
+
+           (void) memmove((char *) &argwr.file,
+                               (char *) &Io_files[filenum].fh3,
+                               sizeof (nfs_fh3));
+           argwr.data.data_len = block.len +
+                                 sizeof(block.len) + sizeof(block.sum);
+           argwr.count = argwr.data.data_len;
+
+           verror(VAL_VERBOSE, I,
+                   "validating write %d bytes @ offset %lu to %s ...\n",
+                   argwr.data.data_len, argwr.offset._p._l,
+                   Io_files[filenum].file_name);
+
+           val_op_write(&argwr, &repwr);
+
+           if (repwr.status == NFS3_OK) {
+               (void) compare_fattr(Ops[WRITE].name, Io_files[filenum].file_name,
+                             &Io_files[filenum].attributes3,
+                             &repwr.resok.file_wcc.after.attr);
+               Io_files[filenum].attributes3 = repwr.resok.file_wcc.after.attr;
+                /*
+                 * XXX-bookeeping kludge.
+                 *
+                 * Need to update hardlink attributes, so readdirplus vali-
+                 * dation doesn't barf.  This is necessary because setattr was
+                 * validated on all the test files and the attributes in
+                 * Io_files[] were updated accordingly.  Since the write
+                 * op has been validated on just the regular files, we have to
+                 * make sure that the corresponding indexes in Io_files[] that
+                 * point to the hard links reflect the current file attributes.
+                 */
+                if (filenum < NUMLINKS) {
+                    Io_files[NUMREGFILES+NUMDIRS+NUMLINKS-1-filenum].attributes3 = Io_files[filenum].attributes3;
+                }
+
+           } else {
+               verror(VAL_BATCH, W, "write %s failed: %m\n",
+                       Io_files[filenum].file_name);
+           }
+       }
+       argwr.offset._p._l += Bytes_per_block;
+    }
+
+    /* validate read */
+
+    for (filenum = 0; filenum < maxfiles; filenum++) {
+       (void) memmove((char *) &argrd.file,
+                       (char *) &Io_files[filenum].fh3,
+                       sizeof (nfs_fh3));
+       argrd.offset._p._u = argrd.offset._p._l = (uint32_t) 0;
+       argrd.count = 0;
+       reprd.resok.data.data_len = 0;
+       maxblks = Io_files[filenum].attributes3.size._p._l / Bytes_per_block;
+       for (blocknum = 0; blocknum <= maxblks; blocknum ++) {
+
+           if (argrd.count != reprd.resok.data.data_len) {
+               argrd.count -= reprd.resok.data.data_len;
+               reprd.resok.data.data_val = (char *)&block +
+                                       reprd.resok.data.data_len;
+               blocknum--;
+           } else {
+               if (blocknum < maxblks)
+                   argrd.count = Bytes_per_block;
+               else
+                   argrd.count = (maxfiles - filenum)
+                                 * (Bytes_per_block/Kb_per_block);
+               reprd.resok.data.data_val = (char *)&block;
+           }
+
+           verror(VAL_VERBOSE, I,
+                  "validating read %lu bytes @ offset %lu from %s ...\n",
+                   argrd.count, argrd.offset._p._l,
+                   Io_files[filenum].file_name);
+
+           val_op_read(&argrd, &reprd);
+
+           if (reprd.status == NFS3_OK) {
+               (void) compare_fattr(Ops[READ].name, Io_files[filenum].file_name,
+                             &Io_files[filenum].attributes3,
+                             &reprd.resok.file_attributes.attr);
+               Io_files[filenum].attributes3 = reprd.resok.file_attributes.attr;
+               argrd.offset._p._l += reprd.resok.data.data_len;
+           } else {
+               verror(VAL_BATCH, W, "read %s failed: %m\n",
+                       Io_files[filenum].file_name);
+           }
+
+           if ((argrd.count ==
+               (block.sum != sum((unsigned char *) &block.len,
+                                 (int)(block.len + sizeof(block.len)))))) {
+               verror(VAL_BATCH, W, "read %s checksum mismatch\n",
+                       Io_files[filenum].file_name);
+           }
+       }
+    }
+
+    /* validate readdir */
+    (void) memmove((char *) &argdr.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+    argdr.cookie._p._l = argdr.cookie._p._u = (uint32_t) 0;
+    (void) memset((char *) argdr.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    argdr.count = DEFAULT_MAX_BUFSIZE;
+
+    do {
+        (void) memset((char *) entry_stream, '\0', sizeof (entry3) * SFS_MAXDIRENTS);
+        (void) memset((char *) &repdr, '\0', sizeof(repdr));
+        repdr.resok.count = SFS_MAXDIRENTS;
+        repdr.resok.reply.entries = entry_stream;
+       verror(VAL_VERBOSE, I, "validating readdir on %s ...\n", Testdirname);
+       val_op_readdir(&argdr, &repdr);
+
+
+       if (repdr.status == NFS3_OK) {
+            for (i = 0; i < repdr.resok.count; i++) {
+                for (filenum = 0; filenum < NUMFILES; filenum++) {
+                    if (!strcmp(entry_stream[i].name, Io_files[filenum].file_name)) {                        if (entry_stream[i].fileid._p._l !=
+                                    Io_files[filenum].attributes3.fileid._p._l) {
+                            verror(VAL_BATCH, E,
+                                "readdir %s error: file %s fileid mismatch\n",
+                                Testdirname, entry_stream[i].name);
+                            verror(VAL_BATCH, W,
+                                "   fileid: got = %lu, original = %lu\n",
+                                entry_stream[i].fileid._p._l,
+                                Io_files[filenum].attributes3.fileid._p._l);
+                        }
+                        /*
+                         * mark file as either found or dup
+                         */
+                        if (check_files[filenum].file_found &&
+                            !check_files[filenum].file_is_dup)
+                                check_files[filenum].file_is_dup = 1;
+                        else
+                                check_files[filenum].file_found = 1;
+                        break;
+                    }
+                }
+            }
+        } else {
+            verror(VAL_BATCH, W, "readdir %s failed: %m\n", Testdirname);
+        }
+
+       argdr.cookie = entry_stream[repdr.resok.count-1].cookie;
+
+    } while (repdr.resok.reply.eof == 0);
+
+    /*
+     * check if any known files have not been found
+     */
+    for (i = 0; i < NUMFILES; i++) {
+        if (!check_files[i].file_found)
+                verror(VAL_BATCH, E,
+                       "readdir %s error: file %s not found\n",
+                       Testdirname, Io_files[i].file_name);
+        else {
+                if (check_files[i].file_is_dup)
+                    verror(VAL_BATCH, E,
+              "readdir %s error: file %s returned more than once\n",
+                           Testdirname, Io_files[i].file_name);
+        }
+    }
+
+    /* validate readdirplus */
+    (void) memset((void *) check_files, '\0', sizeof(check_files));
+
+    argdrp.cookie._p._l = argdrp.cookie._p._u = (uint32_t) 0;
+    (void) memmove((char *) &argdrp.dir, (char *) &Export_dir.fh3,
+                   sizeof (nfs_fh3));
+    (void) memset((char *) argdrp.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
+    /*
+     * We validate readdirplus with dircount and maxcount both set at 8K.
+     * This is not the most efficient way, but this is how readdirplus is
+     * called in SFS.  With the numbers set as such, maxcount becomes the
+     * bottleneck and we will not get 8K worth of directory info.  What we
+     * should get is 8K worth which includes directory info plus post_op_
+     * attributes and filehandle.
+     */
+    argdrp.dircount = DEFAULT_MAX_BUFSIZE;
+    argdrp.maxcount = DEFAULT_MAX_BUFSIZE;
+    do {
+        (void) memset((char *) entryplus_stream, '\0',
+                      sizeof (entryplus_stream));
+
+        (void) memset((char *) &repdrp, '\0', sizeof(repdrp));
+        repdrp.resok.count = SFS_MAXDIRENTS;
+        repdrp.resok.reply.entries = entryplus_stream;
+
+        verror(VAL_VERBOSE, I, "validating readdirplus on %s ...\n",
+                Testdirname);
+        val_op_readdirplus(&argdrp, &repdrp);
+
+        if (repdrp.status == NFS3_OK) {
+            verror(VAL_VERBOSE, I, "readdirplus found %d entries in %s...\n",
+                   repdrp.resok.count, Testdirname);
+            val_rddirplus_retsize(argdrp.dircount, argdrp.maxcount,
+                                  &repdrp.resok);
+            for (i = 0; i < repdrp.resok.count; i++) {
+                for (filenum = 0; filenum < NUMFILES; filenum++) {
+                    if (!strcmp(entryplus_stream[i].name,
+                                Io_files[filenum].file_name)) {
+                        if (entryplus_stream[i].fileid._p._l !=
+                            Io_files[filenum].attributes3.fileid._p._l) {
+                            verror(VAL_BATCH, E,
+                        "readdirplus %s error: file %s fileid mismatch\n",
+                                   Testdirname, entryplus_stream[i].name);
+                            verror(VAL_BATCH, W,
+                                "   fileid: got = %lu, original = %lu\n",
+                                   entryplus_stream[i].fileid._p._l,
+                                   Io_files[filenum].attributes3.fileid._p._l);
+                        }
+
+                        /*
+                         * mark file as either found or dup
+                         */
+                        if (check_files[filenum].file_found &&
+                            !check_files[filenum].file_is_dup)
+                                check_files[filenum].file_is_dup = 1;
+                        else
+                                check_files[filenum].file_found = 1;
+
+                       /*
+                         * check to make sure post op attributes and
+                         * file handle are returned.
+                         */
+                        if (!entryplus_stream[i].name_attributes.attributes)
+                                verror(VAL_BATCH, E,
+                "readdirplus %s warning: did not receive post op attributes for file %s\n\n",
+                                       Testdirname, entryplus_stream[i].name);
+                        else
+                            (void) compare_fattr(Ops[READDIRPLUS].name,
+                                                 Io_files[filenum].file_name,
+                                                 &Io_files[filenum].attributes3,                                                 &entryplus_stream[i].name_attributes.attr);
+
+                        if (!entryplus_stream[i].name_handle.handle_follows)
+                                verror(VAL_BATCH, E,
+                "readdirplus %s warning: did not receive file handle for file %s\n\n",
+                                       Testdirname, entryplus_stream[i].name);
+                        else
+                            if (memcmp((void *) &Io_files[filenum].fh3.fh3_u.data,
+                                       (void *) &entryplus_stream[i].name_handle.handle.fh3_u.data, Io_files[filenum].fh3.fh3_length) != 0)
+                                   verror(VAL_BATCH, E,
+                "readdirplus %s error: file %s, filehandles do not match\n\n",
+                                          Testdirname, entryplus_stream[i].name);
+                        break;
+                    }
+                }
+            }
+        } else {
+            verror(VAL_BATCH, W, "readdirplus %s failed: %m\n", Testdirname);
+        }
+        argdrp.cookie = entryplus_stream[repdrp.resok.count-1].cookie;
+
+    } while (repdrp.resok.reply.eof == 0);
+    /*
+     * check if any known files have not been found
+     */
+    for (i = 0; i < NUMFILES; i++) {
+        if (!check_files[i].file_found)
+                verror(VAL_BATCH, E,
+                       "readdirplus %s error: file %s not found\n",
+                       Testdirname, Io_files[i].file_name);
+        else {
+                if (check_files[i].file_is_dup)
+                    verror(VAL_BATCH, E,
+              "readdirplus %s error: file %s returned more than once\n",
+                           Testdirname, Io_files[i].file_name);
+        }
+    }   
+} /* validate_read_write */
+
+
+static void
+validate_rename(void)
+{
+    RENAME3args argrn;
+    RENAME3res  reprn;
+    int         filenum;
+    char        newname[SFS_MAXNAMLEN];
+    int         rncount = 0;
+
+    (void) memmove((char *) &argrn.from.dir, (char *) &Export_dir.fh3,
+                       sizeof (nfs_fh3));
+    (void) memmove((char *) &argrn.to.dir, (char *) &Export_dir.fh3,
+               sizeof (nfs_fh3));
+
+    for (filenum=0; filenum < NUMFILES; filenum++) {
+       if (Io_files[filenum].state != Exists)
+           continue;
+
+       rncount++;
+       (void) sprintf(newname, "n%s", Io_files[filenum].file_name);
+       argrn.from.name = Io_files[filenum].file_name;
+       argrn.to.name = newname;
+
+       verror(VAL_VERBOSE, I, "validating rename %s %s ...\n",
+               argrn.from.name, argrn.to.name);
+
+       val_op_rename(&argrn, &reprn);
+
+       if (reprn.status == NFS3_OK) {
+           (void) strcpy(Io_files[filenum].file_name, newname);
+       } else {
+           verror(VAL_BATCH, W, "rename %s to %s failed: %m\n",
+                   Io_files[filenum].file_name, newname);
+       }
+
+    }
+
+    if (!rncount) {
+       verror(VAL_BATCH, E, "validate_rename: no files renamed\n");
+       verror(VAL_BATCH, W, "    due to previous operation error\n");
+    }
+
+} /* validate_rename */
+
+
+static int
+compare_fattr(
+    char *      op,
+    char *      fname,
+    fattr3 *     attr1,
+    fattr3 *     attr2)
+{
+    int         ret = TRUE;
+    int         prev_warn = FALSE; /* -1 info warning */
+    int         flag_error = FALSE;
+
+    if (attr1->type != attr2->type) {
+       if (attr1->type == 0xFFFFFFFF) {
+           prev_warn = TRUE;
+           if (ret) {
+               verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                   fname, op);
+           }
+           verror(VAL_BATCH, I, "    type: current = %d, previous =  %d\n",
+                  attr2->type, attr1->type);
+           attr1->type = attr2->type;
+           ret = FALSE;
+       }
+       else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E, "    type: current = %d, previous =  %d\n",
+                       attr2->type, attr1->type);
+               ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if ((attr1->mode & NFSMODE_MASK) != (attr2->mode & NFSMODE_MASK)) {
+       if (attr1->mode == (unsigned int)0xFFFFFFFF) {
+               prev_warn = TRUE;
+               if (ret) {
+                       verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                               fname, op);
+               }
+               verror(VAL_BATCH, I, "    mode: current = %7lo, previous =  %7lo\n",
+                       attr2->mode, attr1->mode);
+               attr1->mode =  attr2->mode;
+               ret = FALSE;
+       }
+       else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E, "    mode: current = %7lo, previous =  %7lo\n",
+                        attr2->mode, attr1->mode);
+               ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if (attr1->nlink != attr2->nlink) {
+       if (attr1->nlink == (unsigned int)0xFFFFFFFF) {
+               prev_warn = TRUE;
+               if (ret) {
+                       verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                               fname, op);
+               }
+               verror(VAL_BATCH, I,
+                       "    nlink: current = %lu, previous =  %lu\n",
+                       attr2->nlink, attr1->nlink);
+               ret = FALSE;
+               attr1->nlink =  attr2->nlink;
+       }
+       else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E,
+                       "    nlink: current = %lu, previous =  %lu\n",
+                       attr2->nlink, attr1->nlink);
+               ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+
+    /*
+     * Check for user "nobody", UID -2, which may be untranslated from
+     * sixteen-bit two's complement.
+     */
+    if (attr1->uid != attr2->uid && !((attr2->uid == (unsigned int)0xFFFFFFFE ||
+       attr2->uid == 65534) && attr1->uid ==0)) {
+       if (attr1->uid == (unsigned int)0xFFFFFFFF) {
+               prev_warn = TRUE;
+               if (ret) {
+                       verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                               fname, op);
+               }
+               verror(VAL_BATCH, I,
+                       "    uid: current = %lu, previous =  %lu\n",
+                       attr2->uid, attr1->uid);
+               attr1->uid =  attr2->uid;
+               ret = FALSE;
+       }
+       else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E,
+                       "    uid: current = %lu, previous =  %lu\n",
+                       attr2->uid, attr1->uid);
+               ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if (attr1->gid != attr2->gid && attr2->gid != 0) {
+/*
+    if (attr1->gid != attr2->gid) {
+*/
+       if (attr1->gid == (unsigned int)0xFFFFFFFF) {
+               prev_warn = TRUE;
+               if (ret) {
+                       verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                               fname, op);
+               }
+               verror(VAL_BATCH, I,
+                       "    gid: current = %lu, previous =  %lu\n",
+                       attr2->gid, attr1->gid);
+               attr1->gid =  attr2->gid;
+               ret = FALSE;
+       }
+       else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E,
+                       "    gid: current = %lu, previous =  %lu\n",
+                       attr2->gid, attr1->gid);
+               ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if (attr1->size._p._l != attr2->size._p._l) {
+       if (strcmp(op, Ops[WRITE].name)) {
+           if (attr1->size._p._l == (unsigned int)0xFFFFFFFF) {
+               prev_warn = TRUE;
+               if (ret) {
+                       verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                               fname, op);
+               }
+               verror(VAL_BATCH, I,
+                       "    size: current = %lu, previous =  %lu\n",
+                       attr2->size._p._l, attr1->size._p._l);
+               attr1->size._p._l =  attr2->size._p._l;
+               ret = FALSE;
+           }
+           else {
+               if (ret) {
+                       verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                           fname, op);
+               }
+               verror(VAL_BATCH, E,
+                       "    size: current = %lu, previous =  %lu\n",
+                       attr2->size._p._l, attr1->size._p._l);
+               ret = FALSE;
+               flag_error = TRUE;
+           }
+       }
+    }
+
+    /* compare rdev only if type == NFCHR or NFBLK */
+    if ((attr1->type == NF3CHR || attr1->type == NF3BLK) &&
+                       (attr1->rdev.specdata1 != attr2->rdev.specdata1 ||
+                       attr1->rdev.specdata2 != attr2->rdev.specdata2)) {
+       if (attr1->rdev.specdata1 == (unsigned int)0xFFFFFFFF) {
+            prev_warn = TRUE;
+            if (ret) {
+                    verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                            fname, op);
+            }
+            verror(VAL_BATCH, I,
+                       "    rdev: current = %lu %lu, previous =  %lu %lu\n",
+                       attr2->rdev.specdata1, attr2->rdev.specdata2,
+                       attr1->rdev.specdata1, attr1->rdev.specdata2);
+            attr1->rdev.specdata1 =  attr2->rdev.specdata1;
+            attr1->rdev.specdata2 =  attr2->rdev.specdata2;
+            ret = FALSE;
+       }
+       else {
+            if (ret) {
+                    verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                        fname, op);
+            }
+            verror(VAL_BATCH, E,
+                       "    rdev: current = %lu %lu, previous =  %lu %lu\n",
+                       attr2->rdev.specdata1, attr2->rdev.specdata2,
+                       attr1->rdev.specdata1, attr1->rdev.specdata2);
+            ret = FALSE;
+            flag_error = TRUE;
+       }
+    }
+
+    if (attr1->fsid._p._l != attr2->fsid._p._l) {
+       if (attr1->fsid._p._l == (unsigned int)0xFFFFFFFF) {
+            prev_warn = TRUE;
+            if (ret) {
+                    verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                            fname, op);
+            }
+            verror(VAL_BATCH, I, "    fsid: current = %lu, previous =  %lu\n",
+                    attr2->fsid._p._l, attr1->fsid._p._l);
+            attr1->fsid._p._l =  attr2->fsid._p._l;
+            ret = FALSE;
+       }
+       else {
+            if (ret) {
+                    verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                        fname, op);
+            }
+            verror(VAL_BATCH, E, "    fsid: current = %lu, previous =  %lu\n",
+                    attr2->fsid._p._l, attr1->fsid._p._l);
+            ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if (attr1->fileid._p._l != attr2->fileid._p._l) {
+       if (attr1->fileid._p._l == (unsigned int)0xFFFFFFFF) {
+            prev_warn = TRUE;
+            if (ret) {
+                    verror(VAL_BATCH, I, "%s: %s attribute mismatch\n",
+                            fname, op);
+            }
+            verror(VAL_BATCH, I,
+                       "    fileid: current = %lu, previous =  %lu\n",
+                       attr2->fileid._p._l, attr1->fileid._p._l);
+            attr1->fileid._p._l =  attr2->fileid._p._l;
+            ret = FALSE;
+       }
+       else {
+            if (ret) {
+                    verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                        fname, op);
+            }
+            verror(VAL_BATCH, E,
+                       "    fileid: current = %lu, previous =  %lu\n",
+                    attr2->fileid._p._l, attr1->fileid._p._l);
+            ret = FALSE;
+               flag_error = TRUE;
+       }
+    }
+
+    if (prev_warn) {
+       verror(VAL_BATCH, I,
+               "\n        Warning: the previous value of a field is -1,\n");
+       verror(VAL_BATCH, I,
+               "        this resulted from an unused field returned by\n");
+       verror(VAL_BATCH, I,
+               "        the previous operation on this file/directory.\n");
+       verror(VAL_BATCH, I,
+           "        The current value is now stored for future comparison\n\n");
+    }
+
+    if (flag_error)
+       verror(VAL_BATCH, W,"\n");
+
+    return(flag_error);
+
+} /* ckompare_fattr */
+
+
+uint32_t sattr_types[8] =      {
+                         0000000,              /* NF3NON */
+                         0100000,              /* NF3REG */
+                         0040000,              /* NF3DIR */
+                         0060000,              /* NF3BLK */
+                         0020000,              /* NF3CHR */
+                         0120000,              /* NF3LNK */
+                         0140000,              /* NF3SOCK */
+                         0010000 };            /* NF3FIFO */
+static int
+compare_sattr(
+    char *      op,
+    char *      fname,
+    sattr3 *    attr1,
+    fattr3 *    attr2)
+{
+    int         ret = TRUE;
+    char        msg[80];
+
+    msg[0] = '\0';
+
+#ifdef notyet
+    if (attr1->mode.mode.set_it == TRUE &&
+       (((attr1->mode.mode & NFSTYPE_FMT) != sattr_types[attr2->type]) &&
+       ((attr1->mode.mode & NFSTYPE_FMT) != sattr_types[0]) ||
+       ((attr1->mode.mode & NFSMODE_FMT) != (attr2->mode & NFSMODE_FMT)))) {
+       if (ret) {
+           verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                                               fname, op);
+
+       }
+       verror(VAL_BATCH, E, "    mode: returned = %7o, specified = %7o\n",
+                               attr1->mode.mode, attr2->mode);
+       ret = FALSE;
+    }
+#endif
+
+    /*
+     * Check for user "nobody", UID -2, which may be untranslated from
+     * sixteen-bit two's complement.
+     */
+    if (attr1->uid.set_it == TRUE && attr1->uid.uid != attr2->uid &&
+                        !((attr2->uid == (unsigned int)0xFFFFFFFE ||
+                                               attr2->uid == 65534) &&
+                                               attr1->uid.uid == 0)) {
+       if (ret) {
+           verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                                               fname, op);
+       }
+       if (attr1->uid.uid == 0)
+           (void) strcat(msg," (is root UID mapped to other UID?)");
+       verror(VAL_BATCH, E, "    uid: returned = %lu, specified = %lu %s\n",
+                               attr2->uid, attr1->uid.uid, msg);
+       ret = FALSE;
+    }
+
+    if (attr1->gid.set_it == TRUE && attr1->gid.gid != attr2->gid &&
+                                                       attr2->gid != 0) {
+/*
+   if (attr1->gid.set_it == TRUE && attr1->gid != attr2->gid) {
+*/
+       if (ret) {
+           verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                   fname, op);
+       }
+       verror(VAL_BATCH, E, "    gid: returned = %lu, specified = %lu\n",
+               attr2->gid, attr1->gid.gid);
+       ret = FALSE;
+    }
+
+    if (attr1->size.set_it == TRUE &&
+                               attr1->size.size._p._l != attr2->size._p._l) {
+       if (ret) {
+           verror(VAL_BATCH, E, "%s: %s attribute mismatch\n",
+                   fname, op);
+       }
+       verror(VAL_BATCH, E, "    size: returned = %lu, specified = %lu\n",
+               attr2->size._p._l, attr1->size.size._p._l);
+       ret = FALSE;
+    }
+
+    if (!ret)
+       verror(VAL_BATCH, W,"\n");
+
+    return(ret);
+
+} /* compare_sattr */
+
+
+/*
+ * Return the BSD checksum of buf[0..len-1]
+ */
+static uint16_t
+sum(
+    unsigned char *     buf,
+    int                 len)
+{
+    uint16_t      cksum;
+
+    cksum = 0;
+    for (; len--; buf++) {
+       if (cksum & 01)
+           cksum = (cksum >> 1) + 0x8000;
+       else
+           cksum >>= 1;
+       cksum += (uint16_t) *buf;
+       cksum &= 0xFFFF;
+    }
+    return(cksum);
+
+} /* sum */
+
+
+static void
+validate_remove(void)
+{
+    REMOVE3args        argrm;
+    REMOVE3res reprm;
+    RMDIR3args argrd;
+    RMDIR3res  reprd;
+    LOOKUP3args        arglp;
+    LOOKUP3res replp;
+    nfsstat3   reply;
+    int         filenum;
+    char *      op;
+
+    for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+       if (Io_files[filenum].state != Exists)
+           continue;
+
+       if (Io_files[filenum].attributes3.type == NF3DIR) {
+           op = Ops[RMDIR].name;
+           verror(VAL_VERBOSE, I, "validating rmdir %s ...\n",
+                   Io_files[filenum].file_name);
+
+           (void) memmove((char *) &argrd.object.dir,
+                               (char *) &Export_dir.fh3,
+                               sizeof (nfs_fh3));
+           argrd.object.name = Io_files[filenum].file_name;
+           val_op_rmdir(&argrd, &reprd);
+           reply = reprd.status;
+       } else {
+           op = Ops[REMOVE].name;
+           verror(VAL_VERBOSE, I, "validating remove %s ...\n",
+                   Io_files[filenum].file_name);
+
+           (void) memmove((char *) &argrm.object.dir, (char *) &Export_dir.fh3,
+                               sizeof (nfs_fh3));
+           argrm.object.name = Io_files[filenum].file_name;
+           val_op_remove(&argrm, &reprm);
+           reply = reprm.status;
+       }
+
+       if (reply == NFS3_OK) {
+           /* make sure the file is removed from the directory */
+           (void) memmove((char *) &arglp.what.dir, (char *) &Export_dir.fh3,
+                               sizeof (nfs_fh3));
+           arglp.what.name = Io_files[filenum].file_name;
+           val_op_lookup(&arglp, &replp);
+
+           if (replp.status == NFS3ERR_NOENT) {
+               Io_files[filenum].state = Nonexistent;
+           } else if (replp.status == NFS3_OK) {
+               verror(VAL_BATCH, W, "%s %s: file not removed\n",
+                      op, Io_files[filenum].file_name);
+           } else {
+               verror(VAL_BATCH, W, "lookup %s failed: %m\n",
+                      Io_files[filenum].file_name);
+
+           }
+       } else {
+           verror(VAL_BATCH, W, "%s %s failed: %m\n", op,
+                   Io_files[filenum].file_name);
+       }
+
+    }
+
+} /* validate_remove */
+
+
+static void
+validate_cleanup(void)
+{
+    free(Io_files);
+    free(Non_io_files);
+    free(Dirs);
+    free(Symlinks);
+    clnt_destroy(NFS_client);
+} /* validate_cleanup */
+
+
+static void
+validate_exit(void)
+{
+    if (!Validate_errors) {
+       verror(VAL_BATCH, I, "validation completed successfully.\n");
+       exit(0);
+    } else {
+       verror(VAL_BATCH, I, "validation terminated with errors\n");
+       exit(1);
+    }
+
+} /* validate_exit */
+
+
+/* PRINTFLIKE3 */ 
+static void
+verror(
+    int         opt,
+    ValMsgType  msgtype,
+    char *      fmt,
+    ...)
+{
+    va_list    ap;
+    char        buf[1024];
+    char *      bp = buf;
+    char *      fp;
+    char *      sp;
+    int         repeat;
+
+    va_start(ap, fmt);
+
+    /*
+     * Expand the "%m" format character into the descriptive string
+     * for the current value of errno.  Printf handles the other "%"
+     * formatting characters.
+     */
+    if (Validate >= opt) {
+       for (fp = fmt; *fp; fp++) {
+           if (*fp == '%' && fp[1] == 'm') {
+               if ((sp = strerror(errno)) == NULL) {
+                   (void) sprintf(bp, "unknown error %d", errno);
+               } else {
+                   (void) strcpy(bp, sp);
+               }
+               bp = buf + strlen(buf);
+               fp++;
+           } else {
+               *bp++ = *fp;
+           }
+       }
+       *bp = '\0';
+       (void) vfprintf(stderr, buf, ap);
+    }
+    va_end(ap);
+
+    if (msgtype != I)
+       Validate_errors++;
+
+    if (msgtype == W && Validate == VAL_INTERACTIVE) {
+       repeat = 1;
+       while (repeat) {
+           char ans[80];
+
+           (void) fprintf(stderr, "continue? (y or n)  ");
+           if (!fgets(ans,80,stdin)) {
+               (void) fprintf(stderr, "\n");
+               continue;
+           }
+           if (ans[0] == 'n' || ans[0] == 'N') {
+               validate_exit();
+               exit(1);
+           } else if (ans[0] == 'y' || ans[0] == 'Y') {
+               repeat = 0;
+               break;
+           }
+       }
+    }
+
+} /* verror */
+
+
+static void
+val_op_null(void)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_NULL, 
+               xdr_void, (char *)0, xdr_void, (char *)0, 
+               Nfs_timers[Ops[NULLCALL].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "null");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_getattr(GETATTR3args *args, GETATTR3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_GETATTR, 
+               xdr_GETATTR3args, (char *)args, xdr_GETATTR3res, (char *)reply, 
+               Nfs_timers[Ops[GETATTR].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "getattr");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_setattr(SETATTR3args *args, SETATTR3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR, 
+               xdr_SETATTR3args, (char *)args, xdr_SETATTR3res, (char *)reply, 
+               Nfs_timers[Ops[SETATTR].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "setattr");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_lookup(LOOKUP3args *args, LOOKUP3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP, 
+               xdr_LOOKUP3args, (char *)args, xdr_LOOKUP3res, (char *)reply, 
+               Nfs_timers[Ops[LOOKUP].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "lookup");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_access(ACCESS3args *args, ACCESS3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_ACCESS, 
+               xdr_ACCESS3args, (char *)args, xdr_ACCESS3res, (char *)reply, 
+               Nfs_timers[Ops[ACCESS].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "access");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_readlink(READLINK3args *args, READLINK3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_READLINK, 
+               xdr_READLINK3args, (char *)args, xdr_READLINK3res, (char *)reply, 
+               Nfs_timers[Ops[READLINK].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "readlink");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_read(READ3args *args, READ3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_READ, 
+               xdr_READ3args, (char *)args, xdr_READ3res, (char *)reply, 
+               Nfs_timers[Ops[READ].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "read");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_write(WRITE3args *args, WRITE3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE, 
+               xdr_WRITE3args, (char *)args, xdr_WRITE3res, (char *)reply, 
+               Nfs_timers[Ops[WRITE].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "write");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_create(CREATE3args *args, CREATE3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE, 
+               xdr_CREATE3args, (char *)args, xdr_CREATE3res, (char *)reply, 
+               Nfs_timers[Ops[CREATE].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "create");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_mkdir(MKDIR3args *args, MKDIR3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR, 
+               xdr_MKDIR3args, (char *)args, xdr_MKDIR3res, (char *)reply, 
+               Nfs_timers[Ops[MKDIR].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "mkdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_symlink(SYMLINK3args *args, SYMLINK3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK, 
+               xdr_SYMLINK3args, (char *)args, xdr_SYMLINK3res, (char *)reply, 
+               Nfs_timers[Ops[SYMLINK].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "symlink");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_mknod(MKNOD3args *args, MKNOD3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_MKNOD, 
+               xdr_MKNOD3args, (char *)args, xdr_MKNOD3res, (char *)reply, 
+               Nfs_timers[Ops[MKNOD].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "mknod");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_remove(REMOVE3args *args, REMOVE3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE, 
+               xdr_REMOVE3args, (char *)args, xdr_REMOVE3res, (char *)reply, 
+               Nfs_timers[Ops[REMOVE].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "remove");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_rmdir(RMDIR3args *args, RMDIR3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR, 
+               xdr_RMDIR3args, (char *)args, xdr_RMDIR3res, (char *)reply, 
+               Nfs_timers[Ops[RMDIR].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "rmdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_rename(RENAME3args *args, RENAME3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME, 
+               xdr_RENAME3args, (char *)args, xdr_RENAME3res, (char *)reply, 
+               Nfs_timers[Ops[RENAME].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "rename");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_link(LINK3args *args, LINK3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_LINK, 
+               xdr_LINK3args, (char *)args, xdr_LINK3res, (char *)reply, 
+               Nfs_timers[Ops[LINK].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, 
+                   "link");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_readdir(READDIR3args *args, READDIR3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIR, 
+               xdr_READDIR3args, (char *)args, xdr_READDIR3res, (char *)reply, 
+               Nfs_timers[Ops[READDIR].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "readdir");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client,
+               NFSPROC3_READDIRPLUS, xdr_READDIRPLUS3args, (char *)args, 
+               xdr_READDIRPLUS3res, (char *)reply, 
+               Nfs_timers[Ops[READDIRPLUS].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client,
+                   "readdirplus");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_fsstat(FSSTAT3args *args, FSSTAT3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_FSSTAT, 
+               xdr_FSSTAT3args, (char *)args, xdr_FSSTAT3res, (char *)reply, 
+               Nfs_timers[Ops[FSSTAT].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "fsstat");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_fsinfo(FSINFO3args *args, FSINFO3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_FSINFO, 
+               xdr_FSINFO3args, (char *)args, xdr_FSINFO3res, (char *)reply, 
+               Nfs_timers[Ops[FSINFO].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "fsinfo");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_pathconf(PATHCONF3args *args, PATHCONF3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_PATHCONF, 
+               xdr_PATHCONF3args, (char *)args, xdr_PATHCONF3res, (char *)reply, 
+               Nfs_timers[Ops[PATHCONF].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "pathconf");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+val_op_commit(COMMIT3args *args, COMMIT3res *reply)
+{
+       int rpc_stat;
+       /* CONSTCOND */
+       while (1) {
+           rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT, 
+               xdr_COMMIT3args, (char *)args, xdr_COMMIT3res, (char *)reply, 
+               Nfs_timers[Ops[COMMIT].call_class]);
+           if (rpc_stat == RPC_SUCCESS)
+               break;
+           if (rpc_stat != RPC_TIMEDOUT) {
+               clnt_perror(NFS_client, "commit");
+               Validate_errors++;
+               validate_exit();
+           }
+       }
+}
+
+static void
+create_3tmp_handles(void)
+{
+       int filenum;
+       for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+               if(Io_files[filenum].fh_data == (sfs_fh_data *)0)
+               {
+                       Io_files[filenum].fh_data = 
+                                       calloc(1,sizeof(sfs_fh_data));
+                       Io_files[filenum].attributes2.type = NFNON;
+                       Io_files[filenum].attributes3.type = NF3NON;
+               }
+       }
+}
+
+static void
+delete_3tmp_handles(void)
+{
+       int filenum;
+       for (filenum = 0; filenum < NUMFILES; filenum++) {
+
+               if(Io_files[filenum].fh_data != (sfs_fh_data *)0)
+               {
+                       free(Io_files[filenum].fh_data);
+                       Io_files[filenum].fh_data= (sfs_fh_data *)0;
+               }
+       }
+}
+/* sfs_3_vld.c */
diff --git a/TBBT/trace_play/sfs_3_xdr.c b/TBBT/trace_play/sfs_3_xdr.c
new file mode 100644 (file)
index 0000000..01a69fb
--- /dev/null
@@ -0,0 +1,1720 @@
+#ifndef lint
+static char sfs_3_xdrSid[] = "@(#)sfs_3_xdr.c 2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *              6585 Merchant Place, Suite 100
+ *              Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * -------------------------- sfs_3_xdr.c --------------------------
+ *
+ *      XDR routines for the nfs protocol.
+ *
+ *.Exported_routines
+ *     xdr_GETATTR3args(XDR *, GETATTR3args *)
+ *     xdr_GETATTR3res(XDR *, GETATTR3res *)
+ *     xdr_SETATTR3args(XDR *, SETATTR3args *)
+ *     xdr_SETATTR3res(XDR *, SETATTR3res *)
+ *     xdr_LOOKUP3args(XDR *, LOOKUP3args *)
+ *     xdr_LOOKUP3res(XDR *, LOOKUP3res *)
+ *     xdr_ACCESS3args(XDR *, ACCESS3args *)
+ *     xdr_ACCESS3res(XDR *, ACCESS3res *)
+ *     xdr_READLINK3args(XDR *, READLINK3args *)
+ *     xdr_READLINK3res(XDR *, READLINK3res *)
+ *     xdr_READ3args(XDR *, READ3args *)
+ *     xdr_READ3res(XDR *, READ3res *)
+ *     xdr_WRITE3args(XDR *, WRITE3args *)
+ *     xdr_WRITE3res(XDR *, WRITE3res *)
+ *     xdr_CREATE3args(XDR *, CREATE3args *)
+ *     xdr_CREATE3res(XDR *, CREATE3res *)
+ *     xdr_MKDIR3args(XDR *, MKDIR3args *)
+ *     xdr_MKDIR3res(XDR *, MKDIR3res *)
+ *     xdr_SYMLINK3args(XDR *, SYMLINK3args *)
+ *     xdr_SYMLINK3res(XDR *, SYMLINK3res *)
+ *     xdr_MKNOD3args(XDR *, MKNOD3args *)
+ *     xdr_MKNOD3res(XDR *, MKNOD3res *)
+ *     xdr_REMOVE3args(XDR *, REMOVE3args *)
+ *     xdr_REMOVE3res(XDR *, REMOVE3res *)
+ *     xdr_RMDIR3args(XDR *, RMDIR3args *)
+ *     xdr_RMDIR3res(XDR *, RMDIR3res *)
+ *     xdr_RENAME3args(XDR *, RENAME3args *)
+ *     xdr_RENAME3res(XDR *, RENAME3res *)
+ *     xdr_LINK3args(XDR *, LINK3args *)
+ *     xdr_LINK3res(XDR *, LINK3res *)
+ *     xdr_READDIR3args(XDR *, READDIR3args *)
+ *     xdr_READDIR3res(XDR *, READDIR3res *)
+ *     xdr_READDIRPLUS3args(XDR *, READDIRPLUS3args *)
+ *     xdr_READDIRPLUS3res(XDR *, READDIRPLUS3res *)
+ *     xdr_FSSTAT3args(XDR *, FSSTAT3args *)
+ *     xdr_FSSTAT3res(XDR *, FSSTAT3res *)
+ *     xdr_FSINFO3args(XDR *, FSINFO3args *)
+ *     xdr_FSINFO3res(XDR *, FSINFO3res *)
+ *     xdr_PATHCONF3args(XDR *, PATHCONF3args *)
+ *     xdr_PATHCONF3res(XDR *, PATHCONF3res *)
+ *     xdr_COMMIT3args(XDR *, COMMIT3args *)
+ *     xdr_COMMIT3res(XDR *, COMMIT3res *)
+ *     xdr_mntres3(XDR *, mountres3 *)
+ *
+ *.Local_routines
+ *     xdr_string3(XDR *, char **, unsigned int)
+ *     xdr_filename3(XDR *, filename3 *)
+ *     xdr_nfspath3(XDR *, nfspath3 *)
+ *     xdr_nfs_uint64_t(XDR *, nfs_uint64_t *)
+ *     xdr_cookieverf3(XDR *, cookieverf3)
+ *     xdr_createverf3(XDR *, createverf3)
+ *     xdr_writeverf3(XDR *, writeverf3)
+ *     xdr_nfs_fh3(XDR *, nfs_fh3 *)
+ *     xdr_diropargs3(XDR *, diropargs3 *)
+ *     xdr_nfstime3(XDR *, nfstime3 *)
+ *     xdr_specdata3(XDR *, specdata3 *)
+ *     xdr_nfsstat3(XDR *, nfsstat3 *)
+ *     xdr_ftype3(XDR *, ftype3 *)
+ *     xdr_fattr3(XDR *, fattr3 *)
+ *     xdr_post_op_attr(XDR *, post_op_attr *)
+ *     xdr_wcc_attr(XDR *, wcc_attr *)
+ *     xdr_pre_op_attr(XDR *, pre_op_attr *)
+ *     xdr_wcc_data(XDR *, wcc_data *)
+ *     xdr_post_op_fh3(XDR *, post_op_fh3 *)
+ *     xdr_time_how(XDR *, time_how *)
+ *     xdr_set_mode3(XDR *, set_mode3 *)
+ *     xdr_set_uid3(XDR *, set_uid3 *)
+ *     xdr_set_gid3(XDR *, set_gid3 *)
+ *     xdr_set_size3(XDR *, set_size3 *)
+ *     xdr_set_atime(XDR *, set_atime *)
+ *     xdr_set_mtime(XDR *, set_mtime *)
+ *     xdr_sattr3(XDR *, sattr3 *)
+ *     xdr_GETATTR3resok(XDR *, GETATTR3resok *)
+ *     xdr_sattrguard3(XDR *, sattrguard3 *)
+ *     xdr_SETATTR3resok(XDR *, SETATTR3resok *)
+ *     xdr_SETATTR3resfail(XDR *, SETATTR3resfail *)
+ *     xdr_LOOKUP3resok(XDR *, LOOKUP3resok *)
+ *     xdr_LOOKUP3resfail(XDR *, LOOKUP3resfail *)
+ *     xdr_ACCESS3resok(XDR *, ACCESS3resok *)
+ *     xdr_ACCESS3resfail(XDR *, ACCESS3resfail *)
+ *     xdr_READLINK3resok(XDR *, READLINK3resok *)
+ *     xdr_READLINK3resfail(XDR *, READLINK3resfail *)
+ *     xdr_READ3resok(XDR *, READ3resok *)
+ *     xdr_READ3resfail(XDR *, READ3resfail *)
+ *     xdr_stable_how(XDR *, stable_how *)
+ *     xdr_WRITE3resok(XDR *, WRITE3resok *)
+ *     xdr_WRITE3resfail(XDR *, WRITE3resfail *)
+ *     xdr_createmode3(XDR *, createmode3 *)
+ *     xdr_createhow3(XDR *, createhow3 *)
+ *     xdr_CREATE3resok(XDR *, CREATE3resok *)
+ *     xdr_CREATE3resfail(XDR *, CREATE3resfail *)
+ *     xdr_MKDIR3resok(XDR *, MKDIR3resok *)
+ *     xdr_MKDIR3resfail(XDR *, MKDIR3resfail *)
+ *     xdr_symlinkdata3(XDR *, symlinkdata3 *)
+ *     xdr_SYMLINK3resok(XDR *, SYMLINK3resok *)
+ *     xdr_SYMLINK3resfail(XDR *, SYMLINK3resfail *)
+ *     xdr_devicedata3(XDR *, devicedata3 *)
+ *     xdr_mknoddata3(XDR *, mknoddata3 *)
+ *     xdr_MKNOD3resok(XDR *, MKNOD3resok *)
+ *     xdr_MKNOD3resfail(XDR *, MKNOD3resfail *)
+ *     xdr_REMOVE3resok(XDR *, REMOVE3resok *)
+ *     xdr_REMOVE3resfail(XDR *, REMOVE3resfail *)
+ *     xdr_RMDIR3resok(XDR *, RMDIR3resok *)
+ *     xdr_RMDIR3resfail(XDR *, RMDIR3resfail *)
+ *     xdr_RENAME3resok(XDR *, RENAME3resok *)
+ *     xdr_RENAME3resfail(XDR *, RENAME3resfail *)
+ *     xdr_LINK3resok(XDR *, LINK3resok *)
+ *     xdr_LINK3resfail(XDR *, LINK3resfail *)
+ *     xdr_getdirlist(XDR *, READDIR3resok *)
+ *     xdr_READDIR3resok(XDR *, READDIR3resok *)
+ *     xdr_READDIR3resfail(XDR *, READDIR3resfail *)
+ *     xdr_getdirpluslist(XDR *, READDIRPLUS3resok *)
+ *     xdr_READDIRPLUS3resok(XDR *, READDIRPLUS3resok *)
+ *     xdr_READDIRPLUS3resfail(XDR *, READDIRPLUS3resfail *)
+ *     xdr_FSSTAT3resok(XDR *, FSSTAT3resok *)
+ *     xdr_FSSTAT3resfail(XDR *, FSSTAT3resfail *)
+ *     xdr_FSINFO3resok(XDR *, FSINFO3resok *)
+ *     xdr_FSINFO3resfail(XDR *, FSINFO3resfail *)
+ *     xdr_PATHCONF3resok(XDR *, PATHCONF3resok *)
+ *     xdr_PATHCONF3resfail(XDR *, PATHCONF3resfail *)
+ *     xdr_COMMIT3resok(XDR *, COMMIT3resok *)
+ *     xdr_COMMIT3resfail(XDR *, COMMIT3resfail *)
+ *
+ *.Revision_History
+ *      28-Jun-94      ChakChung Ng    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+
+/*
+ * -----------------------  SFS XDR Routines  -------------------------
+ */
+
+/*
+ * xdr_string3 deals with "C strings" - arrays of bytes that are terminated by
+ * a NULL character.  The parameter cpp references a pointer to storage. If the
+ * pointer is null, then necessary storage is allocated.  The last parameter is
+ * the max allowed length of the string as allowed by the system.  The NFS
+ * Version 3 protocol does not place limits on strings, but the implementation
+ * needs to place a reasonable limit to avoid problems.
+ */
+
+static bool_t
+xdr_string3(
+    XDR *              xdrs,
+    char **            cpp,
+    unsigned int       maxsize)
+{
+       char *sp;
+       unsigned int size, nodesize;
+
+       /*
+        * first deal with the length since xdr strings are counted-strings
+        */
+       sp = *cpp;
+       switch (xdrs->x_op) {
+       case XDR_FREE:
+               if (sp == NULL || sp == nfs3nametoolong)
+                       return(TRUE);  /* already free */
+               /* FALLTHROUGH */
+       case XDR_ENCODE:
+               size = strlen(sp);
+               break;
+       }
+
+       if (!xdr_u_int(xdrs, &size))
+               return(FALSE);
+
+       /*
+        * now deal with the actual bytes
+        */
+       switch (xdrs->x_op) {
+       case XDR_DECODE:
+               if (size > maxsize) {
+                       int xskp = (((((int)size) + 3) / 4) * 4);
+
+                       *cpp = nfs3nametoolong;
+                       if ((xdrs->x_handy -= xskp) < 0)
+                               return(FALSE);
+                       xdrs->x_private += xskp;
+                       return(TRUE);
+               }
+               nodesize = size + 1;
+               if (nodesize == 0)
+                       return(TRUE);
+               if (sp == NULL) {
+                       sp = (char *)malloc(nodesize);
+                       *cpp = sp;
+                       if (sp == NULL)
+                               return(FALSE);
+               }
+               sp[size] = 0;   /* 0 through size-1 are original string */
+               /* FALLTHROUGH */
+       case XDR_ENCODE:
+               return(xdr_opaque(xdrs, sp, size));
+       case XDR_FREE:
+               nodesize = size + 1;
+               mem_free((caddr_t)sp, nodesize);
+               *cpp = NULL;
+               return(TRUE);
+       }
+
+       return(FALSE);
+}
+
+static bool_t
+xdr_filename3(
+    XDR *              xdrs,
+    filename3 *                objp)
+{
+
+       return(xdr_string3(xdrs, objp, NFS_MAXNAMLEN));
+}
+
+static bool_t
+xdr_nfspath3(
+    XDR *              xdrs,
+    nfspath3 *         objp)
+{
+
+       return(xdr_string3(xdrs, objp, NFS_MAXPATHLEN));
+}
+
+static bool_t
+xdr_nfs_uint64_t(
+    XDR                        *xdrs,
+    nfs_uint64_t *     objp)
+{
+       return(xdr_int(xdrs, (int *)&objp->_p._u) &&
+                                       xdr_int(xdrs, (int *)&objp->_p._l));
+}
+
+static bool_t
+xdr_cookieverf3(
+    XDR *              xdrs,
+    cookieverf3                objp)
+{
+       return(xdr_opaque(xdrs, objp, NFS3_COOKIEVERFSIZE));
+}
+
+static bool_t
+xdr_createverf3(
+    XDR *              xdrs,
+    createverf3                objp)
+{
+       return(xdr_opaque(xdrs, objp, NFS3_CREATEVERFSIZE));
+}
+
+static bool_t
+xdr_writeverf3(
+    XDR *              xdrs,
+    writeverf3         objp)
+{
+       return(xdr_opaque(xdrs, objp, NFS3_WRITEVERFSIZE));
+}
+
+static bool_t
+xdr_nfs_fh3(
+    XDR *              xdrs,
+    nfs_fh3 *          objp)
+{
+       if (!xdr_u_int(xdrs, &objp->fh3_length))
+               return(FALSE);
+
+       if (objp->fh3_length > NFS3_FHSIZE)
+               return(FALSE);
+       if (xdrs->x_op == XDR_DECODE || xdrs->x_op == XDR_ENCODE)
+               return(xdr_opaque(xdrs, objp->fh3_u.data, objp->fh3_length));
+
+       if (xdrs->x_op == XDR_FREE)
+               return(TRUE);
+
+       return(FALSE);
+}
+
+static bool_t
+xdr_diropargs3(
+    XDR *              xdrs,
+    diropargs3 *       objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->dir))
+               return(xdr_filename3(xdrs, &objp->name));
+       return(FALSE);
+}
+
+static bool_t
+xdr_nfstime3(
+    XDR *              xdrs,
+    nfstime3 *         objp)
+{
+       if (xdr_uint32_t(xdrs, &objp->seconds))
+               return(xdr_uint32_t(xdrs, &objp->nseconds));
+       return(FALSE);
+}
+
+static bool_t
+xdr_specdata3(
+    XDR *              xdrs,
+    specdata3 *                objp)
+{
+       if (xdr_uint32_t(xdrs, &objp->specdata1))
+               return(xdr_uint32_t(xdrs, &objp->specdata2));
+       return(FALSE);
+}
+
+static bool_t
+xdr_nfsstat3(
+    XDR *              xdrs,
+    nfsstat3 *         objp)
+{
+       return(xdr_enum(xdrs, (enum_t *)objp));
+}
+
+static bool_t
+xdr_ftype3(
+    XDR *              xdrs,
+    ftype3 *           objp)
+{
+       return(xdr_enum(xdrs, (enum_t *)objp));
+}
+
+static bool_t
+xdr_fattr3(
+    XDR *              xdrs,
+    fattr3 *           objp)
+{
+       if (!xdr_ftype3(xdrs, &objp->type))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->mode))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->nlink))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->uid))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->gid))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->size))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->used))
+               return(FALSE);
+       if (!xdr_specdata3(xdrs, &objp->rdev))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->fsid))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->fileid))
+               return(FALSE);
+       if (!xdr_nfstime3(xdrs, &objp->atime))
+               return(FALSE);
+       if (!xdr_nfstime3(xdrs, &objp->mtime))
+               return(FALSE);
+       if (!xdr_nfstime3(xdrs, &objp->ctime))
+               return(FALSE);
+       return(TRUE);
+}
+static bool_t
+xdr_post_op_attr(
+    XDR *              xdrs,
+    post_op_attr *     objp)
+{
+       if (!xdr_bool(xdrs, &objp->attributes))
+               return(FALSE);
+       switch (objp->attributes) {
+       case TRUE:      return(xdr_fattr3(xdrs, &objp->attr));
+       case FALSE:     return(TRUE);
+       default:        return(FALSE);
+       }
+}
+
+static bool_t
+xdr_wcc_attr(
+    XDR *              xdrs,
+    wcc_attr *         objp)
+{
+       if (xdr_nfs_uint64_t(xdrs, &objp->size) &&
+                                       xdr_nfstime3(xdrs, &objp->mtime))
+               return(xdr_nfstime3(xdrs, &objp->ctime));
+       return(FALSE);
+}
+
+static bool_t
+xdr_pre_op_attr(
+    XDR *              xdrs,
+    pre_op_attr *      objp)
+{
+       if (!xdr_bool(xdrs, &objp->attributes))
+               return(FALSE);
+       switch (objp->attributes) {
+       case TRUE:      return(xdr_wcc_attr(xdrs, &objp->attr));
+       case FALSE:     return(TRUE);
+       default:        return(FALSE);
+       }
+}
+static bool_t
+xdr_wcc_data(
+    XDR *              xdrs,
+    wcc_data *         objp)
+{
+       if (xdr_pre_op_attr(xdrs, &objp->before))
+               return(xdr_post_op_attr(xdrs, &objp->after));
+       return(FALSE);
+}
+static bool_t
+xdr_post_op_fh3(
+    XDR *              xdrs,
+    post_op_fh3 *      objp)
+{
+       if (!xdr_bool(xdrs, &objp->handle_follows))
+               return(FALSE);
+       switch (objp->handle_follows) {
+       case TRUE:      return(xdr_nfs_fh3(xdrs, &objp->handle));
+       case FALSE:     return(TRUE);
+       default:        return(FALSE);
+       }
+}      
+static bool_t
+xdr_time_how(
+    XDR *              xdrs,
+    time_how *         objp)
+{
+       return(xdr_enum(xdrs, (enum_t *)objp));
+}
+
+static bool_t
+xdr_set_mode3(
+    XDR *              xdrs,
+    set_mode3 *                objp)
+{
+       if (!xdr_bool(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == TRUE)
+               return(xdr_uint32_t(xdrs, &objp->mode));
+       return(TRUE);
+}      
+static bool_t
+xdr_set_uid3(
+    XDR *              xdrs,
+    set_uid3 *         objp)
+{
+       if (!xdr_bool(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == TRUE)
+               return(xdr_uint32_t(xdrs, &objp->uid));
+       return(TRUE);
+}      
+static bool_t
+xdr_set_gid3(
+    XDR *              xdrs,
+    set_gid3 *         objp)
+{
+       if (!xdr_bool(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == TRUE)
+               return(xdr_uint32_t(xdrs, &objp->gid));
+       return(TRUE);
+}
+
+static bool_t
+xdr_set_size3(
+    XDR *              xdrs,
+    set_size3 *                objp)
+{
+       if (!xdr_bool(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == TRUE)
+               return(xdr_nfs_uint64_t(xdrs, &objp->size));
+       return(TRUE);
+}
+
+static bool_t
+xdr_set_atime(
+    XDR *              xdrs,
+    set_atime *                objp)
+{
+       if (!xdr_time_how(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == SET_TO_CLIENT_TIME)
+               return(xdr_nfstime3(xdrs, &objp->atime));
+       return(TRUE);
+}
+
+static bool_t
+xdr_set_mtime(
+    XDR *              xdrs,
+    set_mtime *                objp)
+{
+       if (!xdr_time_how(xdrs, &objp->set_it))
+               return(FALSE);
+       if (objp->set_it == SET_TO_CLIENT_TIME)
+               return(xdr_nfstime3(xdrs, &objp->mtime));
+       return(TRUE);
+}
+
+static bool_t
+xdr_sattr3(
+    XDR *              xdrs,
+    sattr3 *           objp)
+{
+       if (xdr_set_mode3(xdrs, &objp->mode) &&
+                                       xdr_set_uid3(xdrs, &objp->uid) &&
+                                       xdr_set_gid3(xdrs, &objp->gid) &&
+                                       xdr_set_size3(xdrs, &objp->size) &&
+                                       xdr_set_atime(xdrs, &objp->atime))
+               return(xdr_set_mtime(xdrs, &objp->mtime));
+       return(FALSE);
+}
+
+
+bool_t
+xdr_GETATTR3args(
+    XDR *              xdrs,
+    GETATTR3args *     objp)
+{
+       return(xdr_nfs_fh3(xdrs, &objp->object));
+}
+
+static bool_t
+xdr_GETATTR3resok(
+    XDR *              xdrs,
+    GETATTR3resok *    objp)
+{
+       return(xdr_fattr3(xdrs, &objp->obj_attributes));
+}
+
+bool_t
+xdr_GETATTR3res(
+    XDR *              xdrs,
+    GETATTR3res *      objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_GETATTR3resok(xdrs, &objp->resok));
+       return(TRUE);
+}
+
+
+static bool_t
+xdr_sattrguard3(
+    XDR *              xdrs,
+    sattrguard3 *      objp)
+{
+       if (!xdr_bool(xdrs, &objp->check))
+               return(FALSE);
+       switch (objp->check) {
+       case TRUE:      return(xdr_nfstime3(xdrs, &objp->obj_ctime));
+       case FALSE:     return(TRUE);
+       default:        return(FALSE);
+       }
+}
+
+bool_t
+xdr_SETATTR3args(
+    XDR *              xdrs,
+    SETATTR3args *     objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->object) &&
+                               xdr_sattr3(xdrs, &objp->new_attributes))
+               return(xdr_sattrguard3(xdrs, &objp->guard));
+       return(FALSE);
+}
+
+static bool_t
+xdr_SETATTR3resok(
+    XDR *              xdrs,
+    SETATTR3resok *    objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->obj_wcc));
+}
+
+static bool_t
+xdr_SETATTR3resfail(
+    XDR *              xdrs,
+    SETATTR3resfail *  objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->obj_wcc));
+}
+
+bool_t
+xdr_SETATTR3res(
+    XDR *              xdrs,
+    SETATTR3res *      objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_SETATTR3resok(xdrs, &objp->resok));
+       return(xdr_SETATTR3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_LOOKUP3args(
+    XDR *              xdrs,
+    LOOKUP3args *      objp)
+{
+       return(xdr_diropargs3(xdrs, &objp->what));
+}
+static bool_t
+xdr_LOOKUP3resok(
+    XDR *              xdrs,
+    LOOKUP3resok *     objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->object) &&
+                               xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_post_op_attr(xdrs, &objp->dir_attributes));
+       return(FALSE);
+}
+static bool_t
+xdr_LOOKUP3resfail(
+    XDR *              xdrs,
+    LOOKUP3resfail *   objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->dir_attributes));
+}
+bool_t
+xdr_LOOKUP3res(
+    XDR *              xdrs,
+    LOOKUP3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_LOOKUP3resok(xdrs, &objp->resok));
+       return(xdr_LOOKUP3resfail(xdrs, &objp->resfail));
+}      
+
+bool_t
+xdr_ACCESS3args(
+    XDR *              xdrs,
+    ACCESS3args *      objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->object))
+               return(xdr_uint32_t(xdrs, &objp->access));
+       return(FALSE);
+}
+
+static bool_t
+xdr_ACCESS3resok(
+    XDR *              xdrs,
+    ACCESS3resok *     objp)
+{
+       if (xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_uint32_t(xdrs, &objp->access));
+       return(FALSE);
+}
+
+static bool_t
+xdr_ACCESS3resfail(
+    XDR *              xdrs,
+    ACCESS3resfail *   objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->obj_attributes));
+}
+
+bool_t
+xdr_ACCESS3res(
+    XDR *              xdrs,
+    ACCESS3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_ACCESS3resok(xdrs, &objp->resok));
+       return(xdr_ACCESS3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_READLINK3args(
+    XDR *              xdrs,
+    READLINK3args *    objp)
+{
+       return(xdr_nfs_fh3(xdrs, &objp->symlink));
+}
+
+static bool_t
+xdr_READLINK3resok(
+    XDR *              xdrs,
+    READLINK3resok *   objp)
+{
+       if (xdr_post_op_attr(xdrs, &objp->symlink_attributes))
+               return(xdr_nfspath3(xdrs, &objp->data));
+       return(FALSE);
+}
+
+static bool_t
+xdr_READLINK3resfail(
+    XDR *              xdrs,
+    READLINK3resfail * objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->symlink_attributes));
+}
+bool_t
+xdr_READLINK3res(
+    XDR *              xdrs,
+    READLINK3res *     objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_READLINK3resok(xdrs, &objp->resok));
+       return(xdr_READLINK3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_READ3args(
+    XDR *              xdrs,
+    READ3args *                objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->file) &&
+                                       xdr_nfs_uint64_t(xdrs, &objp->offset))
+               return(xdr_uint32_t(xdrs, &objp->count));
+       return(FALSE);
+}
+
+static bool_t
+xdr_READ3resok(
+    XDR *              xdrs,
+    READ3resok *       objp)
+{
+       if (xdr_post_op_attr(xdrs, &objp->file_attributes) &&
+                                       xdr_uint32_t(xdrs, &objp->count) &&
+                                       xdr_bool(xdrs, &objp->eof))
+               return(xdr_bytes(xdrs, (char **)&objp->data.data_val,
+                                       (unsigned int *)&objp->data.data_len,
+                                       ~0));
+       return(FALSE);
+}
+
+static bool_t
+xdr_READ3resfail(
+    XDR *              xdrs,
+    READ3resfail *     objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->file_attributes));
+}
+
+bool_t
+xdr_READ3res(
+    XDR *              xdrs,
+    READ3res *         objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_READ3resok(xdrs, &objp->resok));
+       return(xdr_READ3resfail(xdrs, &objp->resfail));
+}
+
+
+static bool_t
+xdr_stable_how(
+    XDR *              xdrs,
+    stable_how *       objp)
+{
+       return(xdr_enum(xdrs, (enum_t *)objp));
+}
+
+bool_t
+xdr_WRITE3args(
+    XDR *              xdrs,
+    WRITE3args *       objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->file) &&
+                                       xdr_nfs_uint64_t(xdrs, &objp->offset) &&
+                                       xdr_uint32_t(xdrs, &objp->count) &&
+                                       xdr_stable_how(xdrs, &objp->stable))
+               return(xdr_bytes(xdrs, (char **)&objp->data.data_val,
+                                       (unsigned int *)&objp->data.data_len,
+                                       ~0));
+       return(FALSE);
+}
+
+static bool_t
+xdr_WRITE3resok(
+    XDR *              xdrs,
+    WRITE3resok *      objp)
+{
+       if (xdr_wcc_data(xdrs, &objp->file_wcc) &&
+                                       xdr_uint32_t(xdrs, &objp->count) &&
+                                       xdr_stable_how(xdrs, &objp->committed))
+               return(xdr_writeverf3(xdrs, objp->verf));
+       return(FALSE);
+}
+
+static bool_t
+xdr_WRITE3resfail(
+    XDR *              xdrs,
+    WRITE3resfail *    objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->file_wcc));
+}
+
+bool_t
+xdr_WRITE3res(
+    XDR *              xdrs,
+    WRITE3res *                objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_WRITE3resok(xdrs, &objp->resok));
+       return(xdr_WRITE3resfail(xdrs, &objp->resfail));
+}
+
+
+static bool_t
+xdr_createmode3(
+    XDR *              xdrs,
+    createmode3 *      objp)
+{
+       return(xdr_enum(xdrs, (enum_t *)objp));
+}
+
+static bool_t
+xdr_createhow3(
+    XDR *              xdrs,
+    createhow3 *       objp)
+{
+       if (!xdr_createmode3(xdrs, &objp->mode))
+               return(FALSE);
+       switch (objp->mode) {
+       case UNCHECKED:
+       case GUARDED:
+               return(xdr_sattr3(xdrs, &objp->createhow3_u.obj_attributes));
+       case EXCLUSIVE:
+               return(xdr_createverf3(xdrs, objp->createhow3_u.verf));
+       default:
+               return(FALSE);
+       }
+}
+
+bool_t
+xdr_CREATE3args(
+    XDR *              xdrs,
+    CREATE3args *      objp)
+{
+       if (xdr_diropargs3(xdrs, &objp->where))
+               return(xdr_createhow3(xdrs, &objp->how));
+       return(FALSE);
+}
+
+static bool_t
+xdr_CREATE3resok(
+    XDR *              xdrs,
+    CREATE3resok *     objp)
+{
+       if (xdr_post_op_fh3(xdrs, &objp->obj) &&
+                               xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_CREATE3resfail(
+    XDR *              xdrs,
+    CREATE3resfail *   objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_CREATE3res(
+    XDR *              xdrs,
+    CREATE3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_CREATE3resok(xdrs, &objp->resok));
+       return(xdr_CREATE3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_MKDIR3args(
+    XDR *              xdrs,
+    MKDIR3args *       objp)
+{
+       if (xdr_diropargs3(xdrs, &objp->where))
+               return(xdr_sattr3(xdrs, &objp->attributes));
+       return(FALSE);
+}
+
+static bool_t
+xdr_MKDIR3resok(
+    XDR *              xdrs,
+    MKDIR3resok *      objp)
+{
+       if (xdr_post_op_fh3(xdrs, &objp->obj) &&
+                               xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_MKDIR3resfail(
+    XDR *              xdrs,
+    MKDIR3resfail *    objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_MKDIR3res(
+    XDR *              xdrs,
+    MKDIR3res *                objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_MKDIR3resok(xdrs, &objp->resok));
+       return(xdr_MKDIR3resfail(xdrs, &objp->resfail));
+}
+
+
+static bool_t
+xdr_symlinkdata3(
+    XDR *              xdrs,
+    symlinkdata3 *     objp)
+{
+       if (xdr_sattr3(xdrs, &objp->symlink_attributes))
+               return(xdr_nfspath3(xdrs, &objp->symlink_data));
+       return(FALSE);
+}
+
+bool_t
+xdr_SYMLINK3args(
+    XDR *              xdrs,
+    SYMLINK3args *     objp)
+{
+       if (xdr_diropargs3(xdrs, &objp->where))
+               return(xdr_symlinkdata3(xdrs, &objp->symlink));
+       return(FALSE);
+}
+
+static bool_t
+xdr_SYMLINK3resok(
+    XDR *              xdrs,
+    SYMLINK3resok *    objp)
+{
+       if (xdr_post_op_fh3(xdrs, &objp->obj) &&
+                               xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_SYMLINK3resfail(
+    XDR *              xdrs,
+    SYMLINK3resfail *  objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_SYMLINK3res(
+    XDR *              xdrs,
+    SYMLINK3res *      objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_SYMLINK3resok(xdrs, &objp->resok));
+       return(xdr_SYMLINK3resfail(xdrs, &objp->resfail));
+}
+
+
+static bool_t
+xdr_devicedata3(
+    XDR *              xdrs,
+    devicedata3 *      objp)
+{
+       if (xdr_sattr3(xdrs, &objp->dev_attributes))
+               return(xdr_specdata3(xdrs, &objp->spec));
+       return(FALSE);
+}
+
+static bool_t
+xdr_mknoddata3(
+    XDR *              xdrs,
+    mknoddata3 *       objp)
+{
+       if (!xdr_ftype3(xdrs, &objp->type))
+               return(FALSE);
+       switch (objp->type) {
+       case NF3CHR:
+       case NF3BLK:
+               if (!xdr_devicedata3(xdrs, &objp->mknoddata3_u.device))
+                       return(FALSE);
+               break;
+       case NF3SOCK:
+       case NF3FIFO:
+               if (!xdr_sattr3(xdrs, &objp->mknoddata3_u.pipe_attributes))
+                       return(FALSE);
+               break;
+       }
+       return(TRUE);
+}
+
+bool_t
+xdr_MKNOD3args(
+    XDR *              xdrs,
+    MKNOD3args *       objp)
+{
+       if (xdr_diropargs3(xdrs, &objp->where))
+               return(xdr_mknoddata3(xdrs, &objp->what));
+       return(FALSE);
+}
+
+static bool_t
+xdr_MKNOD3resok(
+    XDR *              xdrs,
+    MKNOD3resok *      objp)
+{
+       if (xdr_post_op_fh3(xdrs, &objp->obj) &&
+                               xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_MKNOD3resfail(
+    XDR *              xdrs,
+    MKNOD3resfail *    objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_MKNOD3res(
+    XDR *              xdrs,
+    MKNOD3res *                objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_MKNOD3resok(xdrs, &objp->resok));
+       return(xdr_MKNOD3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_REMOVE3args(
+    XDR *              xdrs,
+    REMOVE3args *      objp)
+{
+       return(xdr_diropargs3(xdrs, &objp->object));
+}
+
+static bool_t
+xdr_REMOVE3resok(
+    XDR *              xdrs,
+    REMOVE3resok *     objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+static bool_t
+xdr_REMOVE3resfail(
+    XDR *              xdrs,
+    REMOVE3resfail *   objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_REMOVE3res(
+    XDR *              xdrs,
+    REMOVE3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_REMOVE3resok(xdrs, &objp->resok));
+       return(xdr_REMOVE3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_RMDIR3args(
+    XDR *              xdrs,
+    RMDIR3args *       objp)
+{
+       return(xdr_diropargs3(xdrs, &objp->object));
+}
+
+static bool_t
+xdr_RMDIR3resok(
+    XDR *              xdrs,
+    RMDIR3resok *      objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+static bool_t
+xdr_RMDIR3resfail(
+    XDR *              xdrs,
+    RMDIR3resfail *    objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->dir_wcc));
+}
+
+bool_t
+xdr_RMDIR3res(
+    XDR *              xdrs,
+    RMDIR3res *                objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_RMDIR3resok(xdrs, &objp->resok));
+       return(xdr_RMDIR3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_RENAME3args(
+    XDR *              xdrs,
+    RENAME3args *      objp)
+{
+       if (xdr_diropargs3(xdrs, &objp->from))
+               return(xdr_diropargs3(xdrs, &objp->to));
+       return(FALSE);
+}
+
+static bool_t
+xdr_RENAME3resok(
+    XDR *              xdrs,
+    RENAME3resok *     objp)
+{
+       if (xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+               return(xdr_wcc_data(xdrs, &objp->todir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_RENAME3resfail(
+    XDR *              xdrs,
+    RENAME3resfail *   objp)
+{
+       if (xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+               return(xdr_wcc_data(xdrs, &objp->todir_wcc));
+       return(FALSE);
+}
+
+bool_t
+xdr_RENAME3res(
+    XDR *              xdrs,
+    RENAME3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_RENAME3resok(xdrs, &objp->resok));
+       return(xdr_RENAME3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_LINK3args(
+    XDR *              xdrs,
+    LINK3args *                objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->file))
+               return(xdr_diropargs3(xdrs, &objp->link));
+       return(FALSE);
+}
+
+static bool_t
+xdr_LINK3resok(
+    XDR *              xdrs,
+    LINK3resok *       objp)
+{
+       if (xdr_post_op_attr(xdrs, &objp->file_attributes))
+               return(xdr_wcc_data(xdrs, &objp->linkdir_wcc));
+       return(FALSE);
+}
+
+static bool_t
+xdr_LINK3resfail(
+    XDR *              xdrs,
+    LINK3resfail *     objp)
+{
+       if (xdr_post_op_attr(xdrs, &objp->file_attributes))
+               return(xdr_wcc_data(xdrs, &objp->linkdir_wcc));
+       return(FALSE);
+}
+
+bool_t
+xdr_LINK3res(
+    XDR *              xdrs,
+    LINK3res *         objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_LINK3resok(xdrs, &objp->resok));
+       return(xdr_LINK3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_READDIR3args(
+    XDR *              xdrs,
+    READDIR3args *     objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->dir) &&
+                                       xdr_nfs_uint64_t(xdrs, &objp->cookie) &&
+                                       xdr_cookieverf3(xdrs, objp->cookieverf))
+               return(xdr_uint32_t(xdrs, &objp->count));
+       return(FALSE);
+}
+
+#define        roundtoint(x)   (((x) + sizeof (int) - 1) & ~(sizeof (int) - 1))
+
+/*
+ * DECODE ONLY
+ */
+static bool_t
+xdr_getdirlist(
+    XDR *              xdrs,
+    READDIR3resok *    objp)
+{
+       register int    i;
+       bool_t          valid;
+       unsigned int    namlen;
+       char            name[SFS_MAXNAMLEN];
+       nfs_uint64_t    fileid, cookie;
+       entry3          *dp;
+
+       i = 0;
+       dp = objp->reply.entries;
+       for (;;) {
+               if (!xdr_bool(xdrs, &valid))
+                       return(FALSE);
+               if (!valid)
+                       break;
+               if (!xdr_nfs_uint64_t(xdrs, &fileid) ||
+                                               !xdr_u_int(xdrs, &namlen))
+                       return(FALSE);
+               if (namlen >= SFS_MAXNAMLEN)
+                       namlen = SFS_MAXNAMLEN - 1;
+               if (!xdr_opaque(xdrs, name, namlen) ||
+                                       !xdr_nfs_uint64_t(xdrs, &cookie))
+                       return(FALSE);
+               name[namlen] = '\0';
+               if (i < SFS_MAXDIRENTS) {
+                   dp[i].fileid = fileid;
+                   (void)memmove(dp[i].name, name, (namlen+1));
+                   dp[i].cookie = cookie;
+                   i++;
+               }
+       }
+       objp->count = i;
+       if (!xdr_bool(xdrs, &objp->reply.eof))
+               return(FALSE);
+       return(TRUE);
+}
+
+static bool_t
+xdr_READDIR3resok(
+    XDR *              xdrs,
+    READDIR3resok *    objp)
+{
+       if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+               return(FALSE);
+       if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+               return(FALSE);
+       if (xdrs->x_op == XDR_DECODE)
+               return(xdr_getdirlist(xdrs, objp));
+       return(TRUE);
+}
+
+static bool_t
+xdr_READDIR3resfail(
+    XDR *              xdrs,
+    READDIR3resfail *  objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->dir_attributes));
+}
+
+bool_t
+xdr_READDIR3res(
+    XDR *              xdrs,
+    READDIR3res *      objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_READDIR3resok(xdrs, &objp->resok));
+       return(xdr_READDIR3resfail(xdrs, &objp->resfail));
+}
+
+bool_t
+xdr_READDIRPLUS3args(
+    XDR *              xdrs,
+    READDIRPLUS3args * objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->dir) &&
+                               xdr_nfs_uint64_t(xdrs, &objp->cookie) &&
+                               xdr_cookieverf3(xdrs, objp->cookieverf) &&
+                               xdr_uint32_t(xdrs, &objp->dircount))
+               return(xdr_uint32_t(xdrs, &objp->maxcount));
+       return(FALSE);
+}
+
+/*
+ * copy post_op_attr from s2 to s1
+ */
+static void
+copy_post_op_attr(post_op_attr *s1, post_op_attr *s2)
+{
+       s1->attributes = s2->attributes;
+       (void) memmove((void *) &s1->attr, (void *) &s2->attr,
+                      sizeof (fattr3));
+}
+
+/*
+ * copy post_op_fh3 from s2 to s1
+ */
+static void
+copy_post_op_fh3(post_op_fh3 *s1, post_op_fh3 *s2)
+{
+       s1->handle_follows = s2->handle_follows;
+       (void) memmove((void *) &s1->handle, (void *) &s2->handle,
+                      sizeof (nfs_fh3));
+}
+               
+/*
+ * DECODE ONLY
+ */
+static bool_t
+xdr_getdirpluslist(
+    XDR *              xdrs,
+    READDIRPLUS3resok *        objp)
+{
+       register int    i;
+       bool_t          valid;
+       unsigned int    namlen;
+       char            name[SFS_MAXNAMLEN];
+       nfs_uint64_t    fileid, cookie;
+       entryplus3      *dp;
+       post_op_attr    at;
+       post_op_fh3     fh;
+
+       i = 0;
+       dp = objp->reply.entries;
+       for (;;) {
+               if (!xdr_bool(xdrs, &valid))
+                       return(FALSE);
+               if (!valid)
+                       break;
+               if (!xdr_nfs_uint64_t(xdrs, &fileid) ||
+                                       !xdr_u_int(xdrs, &namlen))
+                       return(FALSE);
+               if (namlen >= SFS_MAXNAMLEN)
+                       namlen = SFS_MAXNAMLEN - 1;
+               if (!xdr_opaque(xdrs, name, namlen) ||
+                                       !xdr_nfs_uint64_t(xdrs, &cookie))
+                       return(FALSE);
+               name[namlen] = '\0';
+               if (!xdr_post_op_attr(xdrs, &at))
+                       return(FALSE);
+               if (!xdr_post_op_fh3(xdrs, &fh))
+                       return(FALSE);
+               if (i < SFS_MAXDIRENTS) {
+                   dp[i].fileid = fileid;
+                   (void)memmove(dp[i].name, name, (namlen+1));
+                   dp[i].cookie = cookie;
+                   copy_post_op_attr(&dp[i].name_attributes, &at);
+                   copy_post_op_fh3(&dp[i].name_handle, &fh);
+                   i++;
+               }
+       }
+
+       objp->count = i;
+       if (!xdr_bool(xdrs, &objp->reply.eof))
+               return(FALSE);
+       return(TRUE);
+}
+
+static bool_t
+xdr_READDIRPLUS3resok(
+    XDR *              xdrs,
+    READDIRPLUS3resok *        objp)
+{
+
+       if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+               return(FALSE);
+       if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+               return(FALSE);
+       if (xdrs->x_op == XDR_DECODE)
+               return(xdr_getdirpluslist(xdrs, objp));
+       return(TRUE);
+}
+
+static bool_t
+xdr_READDIRPLUS3resfail(
+    XDR *                      xdrs,
+    READDIRPLUS3resfail *      objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->dir_attributes));
+}
+
+bool_t
+xdr_READDIRPLUS3res(
+    XDR *              xdrs,
+    READDIRPLUS3res *  objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_READDIRPLUS3resok(xdrs, &objp->resok));
+       return(xdr_READDIRPLUS3resfail(xdrs, &objp->resfail));
+}
+
+bool_t
+xdr_FSSTAT3args(
+    XDR *              xdrs,
+    FSSTAT3args *      objp)
+{
+       return(xdr_nfs_fh3(xdrs, &objp->fsroot));
+}
+
+static bool_t
+xdr_FSSTAT3resok(
+    XDR *              xdrs,
+    FSSTAT3resok *     objp)
+{
+       if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->tbytes))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->fbytes))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->abytes))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->tfiles))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->ffiles))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->afiles))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->invarsec))
+               return(FALSE);
+       return(TRUE);
+}
+
+static bool_t
+xdr_FSSTAT3resfail(
+    XDR *              xdrs,
+    FSSTAT3resfail *   objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->obj_attributes));
+}
+
+bool_t
+xdr_FSSTAT3res(
+    XDR *              xdrs,
+    FSSTAT3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_FSSTAT3resok(xdrs, &objp->resok));
+       return(xdr_FSSTAT3resfail(xdrs, &objp->resfail));
+}
+
+bool_t
+xdr_FSINFO3args(
+    XDR *              xdrs,
+    FSINFO3args *      objp)
+{
+       return(xdr_nfs_fh3(xdrs, &objp->fsroot));
+}
+
+static bool_t
+xdr_FSINFO3resok(
+    XDR *              xdrs,
+    FSINFO3resok *     objp)
+{
+       if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->rtmax))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->rtpref))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->rtmult))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->wtmax))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->wtpref))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->wtmult))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->dtpref))
+               return(FALSE);
+       if (!xdr_nfs_uint64_t(xdrs, &objp->maxfilesize))
+               return(FALSE);
+       if (!xdr_nfstime3(xdrs, &objp->time_delta))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->properties))
+               return(FALSE);
+       return(TRUE);
+}
+
+static bool_t
+xdr_FSINFO3resfail(
+    XDR *              xdrs,
+    FSINFO3resfail *   objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->obj_attributes));
+}
+
+bool_t
+xdr_FSINFO3res(
+    XDR *              xdrs,
+    FSINFO3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_FSINFO3resok(xdrs, &objp->resok));
+       return(xdr_FSINFO3resfail(xdrs, &objp->resfail));
+}
+
+bool_t
+xdr_PATHCONF3args(
+    XDR *              xdrs,
+    PATHCONF3args *    objp)
+{
+       return(xdr_nfs_fh3(xdrs, &objp->object));
+}
+
+static bool_t
+xdr_PATHCONF3resok(
+    XDR *              xdrs,
+    PATHCONF3resok *   objp)
+{
+       if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->link_max))
+               return(FALSE);
+       if (!xdr_uint32_t(xdrs, &objp->name_max))
+               return(FALSE);
+       if (!xdr_bool(xdrs, &objp->no_trunc))
+               return(FALSE);
+       if (!xdr_bool(xdrs, &objp->chown_restricted))
+               return(FALSE);
+       if (!xdr_bool(xdrs, &objp->case_insensitive))
+               return(FALSE);
+       if (!xdr_bool(xdrs, &objp->case_preserving))
+               return(FALSE);
+       return(TRUE);
+}
+
+static bool_t
+xdr_PATHCONF3resfail(
+    XDR *              xdrs,
+    PATHCONF3resfail * objp)
+{
+       return(xdr_post_op_attr(xdrs, &objp->obj_attributes));
+}
+
+bool_t
+xdr_PATHCONF3res(
+    XDR *              xdrs,
+    PATHCONF3res *     objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_PATHCONF3resok(xdrs, &objp->resok));
+       return(xdr_PATHCONF3resfail(xdrs, &objp->resfail));
+}
+
+bool_t
+xdr_COMMIT3args(
+    XDR *              xdrs,
+    COMMIT3args *      objp)
+{
+       if (xdr_nfs_fh3(xdrs, &objp->file) &&
+                                       xdr_nfs_uint64_t(xdrs, &objp->offset))
+               return(xdr_uint32_t(xdrs, &objp->count));
+       return(FALSE);
+}
+
+static bool_t
+xdr_COMMIT3resok(
+    XDR *              xdrs,
+    COMMIT3resok *     objp)
+{
+       if (xdr_wcc_data(xdrs, &objp->file_wcc))
+               return(xdr_writeverf3(xdrs, objp->verf));
+       return(FALSE);
+}
+
+static bool_t
+xdr_COMMIT3resfail(
+    XDR *              xdrs,
+    COMMIT3resfail *   objp)
+{
+       return(xdr_wcc_data(xdrs, &objp->file_wcc));
+}
+
+bool_t
+xdr_COMMIT3res(
+    XDR *              xdrs,
+    COMMIT3res *       objp)
+{
+       if (!xdr_nfsstat3(xdrs, &objp->status))
+               return(FALSE);
+       if (objp->status == NFS3_OK)
+               return(xdr_COMMIT3resok(xdrs, &objp->resok));
+       return(xdr_COMMIT3resfail(xdrs, &objp->resfail));
+}
+
+
+bool_t
+xdr_dirpath(
+    XDR *              xdrs,
+    dirpath *          objp)
+{
+       return(xdr_string(xdrs, objp, MNTPATHLEN));
+}
+
+static bool_t
+xdr_fhandle3(
+    XDR *              xdrs,
+    fhandle3 *         objp)
+{
+       return(xdr_bytes(xdrs, (char **) &objp->fhandle3_val,
+                               (unsigned int *) &objp->fhandle3_len, NFS3_FHSIZE));
+}
+
+static bool_t
+xdr_mntres3_ok(
+    XDR *              xdrs,
+    mntres3_ok *       objp)
+{
+       if (xdr_fhandle3(xdrs, &objp->fhandle)) {
+               return(xdr_array(xdrs,
+                       (void **) &objp->auth_flavors.auth_flavors_val,
+                       (unsigned int *) &objp->auth_flavors.auth_flavors_len,
+                       ~0, sizeof (int), (xdrproc_t) xdr_int));
+       }
+       return(FALSE);
+}
+
+bool_t
+xdr_mntres3(
+    XDR *              xdrs,
+    mountres3 *                objp)
+{
+       if (!xdr_enum(xdrs, (enum_t *) &objp->fhs_status))
+               return(FALSE);
+       if (objp->fhs_status == MNT_OK)
+               return(xdr_mntres3_ok(xdrs, &objp->mntres3_u.mntinfo));
+       return(TRUE);
+}
+/* sfs_3_xdr.c */
diff --git a/TBBT/trace_play/sfs_c_bio.c b/TBBT/trace_play/sfs_c_bio.c
new file mode 100644 (file)
index 0000000..ed35c42
--- /dev/null
@@ -0,0 +1,1023 @@
+#ifndef lint
+static char sfs_c_bioSid[] = "@(#)sfs_c_bio.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * ---------------------- sfs_c_bio.c ---------------------
+ *
+ *     Routines that attempt to simulate biod behavior
+ *
+ *     The routines contained here model biod behavior.  Simply call
+ *     biod_init() to replace regular calls to op_read() and op_write()
+ *     with calls to op_biod_read() and op_biod_write().  The variables
+ *     max_out_writes and max_out_reads control the maximum number of
+ *     outstanding writes and reads respectively.
+ *
+ *.Exported Routines
+ *     int     biod_init(int, int);
+ *     void    biod_turn_on(void);
+ *     void    op_biod_write(int, int, int);
+ *     void    op_biod_read(int);
+ *
+ *.Local Routines
+ *     uint32_t        biod_clnt_call(CLIENT *, uint32_t,
+ *                                             xdrproc_t, void *);
+ *     struct biod_req *biod_get_reply(CLIENT *, xdrproc_t,
+ *                                             void *, struct timeval *);
+ *     int             biod_poll_wait(CLIENT *, uint32_t);
+ *
+ *.Revision_History
+ *     03-May-94       Robinson
+ *                             History now kept in SCCS
+ *     03-Mar-92       0.1.0 Corbin
+ *                                     Added biod behavior
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "rfs_c_def.h"
+
+/*
+ * Information associated with outstanding read/write requests
+ */
+#ifndef RFS
+struct biod_req {
+    uint32_t           xid;            /* RPC transmission ID  */
+    bool_t             in_use;                 /* Indicates if the entry is in use */
+       int     dep_tab_index;                  /* corresponding index in dep_tab */
+    unsigned int       count;          /* Count saved for Dump routines */
+    unsigned int       offset;         /* Offset saved for Dump routines */
+    struct ladtime     start;          /* Time RPC call was made */
+    struct ladtime     stop;           /* Time RPC reply was received */
+    struct ladtime     timeout;        /* Time RPC call will time out */
+};
+#endif
+
+/*
+ * ----------------------  Static Declarations  ----------------------
+ */
+
+static int     max_out_writes;
+static int     max_out_reads;
+int    max_biod_reqs = 0;
+struct biod_req *biod_reqp;
+
+/* forward definitions for local functions */
+extern uint32_t        biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+static struct biod_req *biod_get_reply(CLIENT *, xdrproc_t,
+                                               void *, struct timeval *);
+extern int     biod_poll_wait(CLIENT *, uint32_t);
+
+static int op_biod_write(int, int, int);
+static int op_biod_read(int);
+
+/*
+ * ----------------------  BIOD Support Routines  ----------------------
+ */
+
+/*
+ * biod_init()
+ *
+ * This function is called during the initialization phase. It performs
+ * the following tasks:
+ *     - Allocate memory to hold outstanding biod request information
+ *
+ * Returns 0 for OK, -1 for failure
+ */
+int
+biod_init(
+    int                        out_writes,
+    int                        out_reads)
+{
+    // RFS max_out_writes = MAXIMUM(1, out_writes);
+    // RFS max_out_reads = MAXIMUM(1, out_reads);
+    // RFS max_biod_reqs = MAXIMUM(out_writes, out_reads);
+       max_biod_reqs = MAX_OUTSTANDING_REQ;    // RFS
+
+    biod_reqp = (struct biod_req *) calloc(max_biod_reqs,
+                                          sizeof (struct biod_req));
+    if (biod_reqp == (struct biod_req *)0) {
+       (void) fprintf(stderr, "%s: biod_init calloc failed.\n", sfs_Myname);
+       (void) fflush(stderr);
+       return (-1);
+    }
+
+    return (0);
+} /* biod_init */
+
+#ifndef RFS
+
+/*
+ *     - Change the operation functions for reads and writes to use the
+ *       biod routines. This step should be done last to allow callers
+ *       to still run with the old op functions if the biod initialization
+ *       fails.
+ */
+void
+biod_turn_on(void)
+{
+    Ops[WRITE].funct = op_biod_write;
+    Ops[READ].funct = op_biod_read;
+}
+
+#endif
+
+/*
+ * biod_term()
+ *
+ * This function is called during the termination phase to free any resources
+ * allocated by the biod_init() routine. It performs the following tasks:
+ *     - Frees memory associated with outstanding biod request information
+ *     - Frees the biod client handle
+ */
+void
+biod_term(void)
+{
+    if (max_biod_reqs) {
+       free(biod_reqp);
+    }
+} /* biod_term */
+
+#ifndef RFS
+/*
+ * Perform and RPC biod style write operation of length 'xfer_size'.
+ * If 'append_flag' is true, then write the data to the end of the file.
+ */
+static int
+op_biod_write(
+    int                        xfer_size,
+    int                        append_flag,
+    int                        stab_flag)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    static char                *buf = NULL;    /* the data buffer */
+    unsigned int       size;           /* size of data write */
+    int                        max_cnt;
+    attrstat           reply2;         /* the reply */
+    writeargs          args2;
+    WRITE3res          reply3;         /* the reply */
+    WRITE3args         args3;
+    struct ladtime     curr_time;
+    struct ladtime     tmp_time;
+    struct ladtime     call_timeout;
+    struct biod_req    *reqp;
+    int                        ret;            /* ret val == call success */
+    int                        num_out_reqs;   /* # of outstanding writes */
+    int                        i;
+    int                        error;
+    int32_t            offset;
+    static int         calls = 0;
+
+    calls++;
+
+    if (nfs_version != NFS_VERSION && nfs_version != NFS_V3)
+       return (0);
+
+    /*
+     * Initialize write buffer to known value
+     */  
+    if (buf == NULL) {
+        buf = init_write_buffer();
+    }
+
+
+    /*
+     * For now we treat DATA_SYNC to be the same as FILE_SYNC.
+     * If it is not a V3 op then it must always be stable
+     */  
+    if (stab_flag == DATA_SYNC || nfs_version != NFS_V3)
+        stab_flag = FILE_SYNC;
+
+    op_ptr = &Ops[WRITE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args2.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args3.file, (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    args2.beginoffset = 0;     /* unused */
+
+    if (append_flag == 1) {
+       args2.offset = Cur_file_ptr->attributes2.size;
+       args3.offset = Cur_file_ptr->attributes3.size;
+    } else {
+       if (fh_size(Cur_file_ptr) > xfer_size) {
+           offset = Bytes_per_block * (sfs_random() %
+                           (((fh_size(Cur_file_ptr) - xfer_size)
+                           / Bytes_per_block) + 1));
+           args2.offset = offset;
+           args3.offset._p._u = 0;
+           args3.offset._p._l = offset;
+       } else {
+           args2.offset = 0;
+           args3.offset._p._u = args3.offset._p._l = 0;
+       }
+    }
+
+    size = Bytes_per_block;
+    args2.totalcount = size;   /* unused */
+    args2.data.data_len = size;
+    args2.data.data_val = buf;
+    args3.data.data_len = size;
+    args3.data.data_val = buf;
+    args3.count = size;
+    args3.stable = stab_flag;
+
+    /* Calculate the number of NFS writes required */
+    max_cnt = xfer_size / Bytes_per_block;
+    if ((xfer_size % Bytes_per_block) != 0) {
+       max_cnt++;
+    }
+
+    /* check our stats to see if this would overflow */
+    if (!Timed_run) {
+       if (op_ptr->target_calls > 0 &&
+          (op_ptr->results.good_calls + max_cnt) > op_ptr->target_calls) {
+           max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+       }
+    }
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "write: %d buffers xfer_size %d\n",
+                         max_cnt, xfer_size);
+       (void) fflush(stderr);
+    }
+
+    /* Mark all request slots as not in use */
+    for (reqp = biod_reqp, i = 0; i < max_biod_reqs; i++, reqp++) {
+       reqp->in_use = FALSE;
+    }
+
+    if (Current_test_phase < Warmup_phase) {
+       call_timeout.sec = Nfs_timers[Init].tv_sec;
+       call_timeout.usec = Nfs_timers[Init].tv_usec;
+    } else {
+       call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+    }
+
+    /* capture length for possible dump */
+    Dump_length = fh_size(Cur_file_ptr);
+    /* make the call(s) now */
+    num_out_reqs = 0;
+    while (xfer_size > 0 || num_out_reqs > 0) {
+       /*
+        * Send out calls async until either the maximum number of outstanding
+        * requests has been reached or there are no more requests to make.
+        */
+       while (num_out_reqs < max_out_writes && xfer_size > 0) {
+
+           /* find an empty write request slot */
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   break;
+               }
+           }
+
+           if (xfer_size < size) {
+               size = xfer_size;
+               args2.data.data_len = xfer_size;
+               args2.totalcount = xfer_size;           /* unused */
+               args3.data.data_len = xfer_size;
+               args3.count = xfer_size;
+           }
+           xfer_size -= size;
+
+           sfs_gettime(&reqp->start);
+           if (nfs_version == NFS_V3) {
+                   reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC3_WRITE,
+                                       xdr_WRITE3args, (char *) &args3);
+                   if (reqp->xid != 0) {
+                       /* capture count and offset for possible dump */
+                       reqp->count = args3.data.data_len;
+                       reqp->offset = args3.offset._p._l;
+                       reqp->timeout = reqp->start;
+                       ADDTIME(reqp->timeout, call_timeout);
+                       reqp->in_use = TRUE;
+                       num_out_reqs++;
+                   }
+           }
+           if (nfs_version == NFS_VERSION) {
+                   reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC_WRITE,
+                                       xdr_write, (char *) &args2);
+                   if (reqp->xid != 0) {
+                       /* capture count and offset for possible dump */
+                       reqp->count = args2.data.data_len;
+                       reqp->offset = args2.offset;
+                       reqp->timeout = reqp->start;
+                       ADDTIME(reqp->timeout, call_timeout);
+                       reqp->in_use = TRUE;
+                       num_out_reqs++;
+                   }
+           }
+           if (DEBUG_CHILD_BIOD) {
+               (void) fprintf (stderr,
+"[%d]:Biod write started xid %x start (%d.%06d) timeo (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec);
+           }
+
+           args2.offset += size;
+           args3.offset._p._l += size;
+           if (biod_poll_wait(NFS_client, 0) > 0) {
+               break;
+           }
+       } /* while can make an async call */
+
+       /*
+        * Process replies while there is data on the socket buffer.
+        * Just do polls on the select, no sleeping occurs in this loop.
+        */
+       do {
+           error = biod_poll_wait(NFS_client, 0);
+           switch (error) {
+               case -1:
+                   if (errno == EINTR) {
+                       error = 1;
+                       continue;
+                   }
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf(stderr, "%s:[%d]: biod_poll_wait error\n",
+                                          sfs_Myname, calls);
+                       (void) fflush(stderr);
+                   }
+                   break;
+
+               case 0:
+                   break;
+
+
+               default:
+                   if (nfs_version == NFS_VERSION)
+                           reqp = biod_get_reply(NFS_client, xdr_write,
+                                         (char *) &reply2,
+                                         &Nfs_timers[op_ptr->call_class]);
+                   if (nfs_version == NFS_V3)
+                           reqp = biod_get_reply(NFS_client, xdr_WRITE3res,
+                                         (char *) &reply3,
+                                         &Nfs_timers[op_ptr->call_class]);
+
+                   /*
+                    * If biod_get_reply returns NULL then we got an RPC
+                    * level error, probably a dropped fragment or the
+                    * remains of a previous partial request.
+                    */
+                   if (reqp == (struct biod_req *)NULL) {
+                       error = 0;
+                       break;
+                   }
+
+                   /*
+                    * We have a valid response, check if procedure completed
+                    * correctly.
+                    */
+                   if ((nfs_version == NFS_VERSION &&
+                        reply2.status == NFS_OK) ||
+                        (nfs_version == NFS_V3 && reply3.status == NFS3_OK)) {
+                       Cur_file_ptr->state = Exists;
+                       /*
+                        * In updating attributes we may get replies out
+                        * of order.  We blindly update the attributes
+                        * which may cause old attributes to be stored.
+                        * XXX We should check for old attributes.
+                        */
+                       if (nfs_version == NFS_VERSION)
+                           Cur_file_ptr->attributes2 =
+                                       reply2.attrstat_u.attributes;
+                       if (nfs_version == NFS_V3)
+                           Cur_file_ptr->attributes3 =
+                                       reply3.res_u.ok.file_wcc.after.attr;
+                       if (DEBUG_CHILD_RPC) {
+                           (void) fprintf(stderr,
+                                       "%s: WRITE %s %d bytes offset %d \n",
+                                       sfs_Myname, Cur_filename,
+                                       reqp->count, reqp->offset);
+                           (void) fflush(stderr);
+                       }
+
+                       /* capture count and offset for possible dump */
+                       Dump_count = reqp->count;
+                       Dump_offset = reqp->offset;
+                       sfs_elapsedtime(op_ptr, &reqp->start, &reqp->stop);
+                       op_ptr->results.good_calls++;
+                       Ops[TOTAL].results.good_calls++;
+                       ret++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf (stderr,
+"[%d]:Biod write succeded xid %x start (%d.%06d) timeo (%d.%06d) stop (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               reqp->stop.sec, reqp->stop.usec);
+                       }
+                   } else {
+                       op_ptr->results.bad_calls++;
+                       Ops[TOTAL].results.bad_calls++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf (stderr,
+"[%d]:Biod write failed xid %x start (%d.%06d) timeo (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec);
+
+                           (void) fprintf(stderr,
+                                   "[%d]:BIOD WRITE FAILED: xid %x",
+                                   calls, reqp->xid);
+
+                           if (nfs_version == NFS_VERSION)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply2.status);
+                           if (nfs_version == NFS_V3)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply3.status);
+                           (void) fprintf(stderr, "\n");
+                       }
+                   }
+                   break;
+           }
+       } while (error > 0 && num_out_reqs > 0);
+
+       /* Scan for replies that have timed out */
+       if (num_out_reqs > 0) {
+           sfs_gettime(&curr_time);
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (reqp->timeout.sec < curr_time.sec ||
+                   (reqp->timeout.sec == curr_time.sec &&
+                   reqp->timeout.usec < curr_time.usec)) {
+
+                   op_ptr->results.bad_calls++;
+                   Ops[TOTAL].results.bad_calls++;
+                   reqp->in_use = FALSE;
+                   num_out_reqs--;
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf (stderr,
+"[%d]:Biod write timed out %x start (%d.%06d) timeo (%d.%06d) now (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               curr_time.sec, curr_time.usec);
+                       if (biod_poll_wait(NFS_client, 0) > 0) {
+                          (void) fprintf(stderr,
+                               "[%d]:BIOD WRITE TIMEOUT - data on input queue!\n", calls);
+                       }
+                   }
+               }
+           }
+       }
+
+       /*
+        * We go to sleep waiting for a reply if all the requests have
+        * been sent and there are outstanding requests, or we cannot
+        * send any more requests.
+        */
+       if ((xfer_size <= 0 && num_out_reqs > 0) ||
+           num_out_reqs == max_out_writes) {
+           /*
+            * Find the next outstanding request that will timeout
+            * and take a time differential to use for the poll timeout.
+            * If the differential is less than zero, then we go to the
+            * top of the loop. Note that we are not picky on errors
+            * returned by select, after the sleep we return to the top
+            * of the loop so extensive error/status checking is not
+            * needed.
+            */
+           tmp_time.sec = 0;
+           tmp_time.usec = 0;
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (tmp_time.sec == 0 ||
+                   (reqp->timeout.sec < tmp_time.sec ||
+                    (reqp->timeout.sec == tmp_time.sec &&
+                     reqp->timeout.usec < tmp_time.usec))) {
+                   
+                    tmp_time = reqp->timeout;
+               }
+           }
+           if (tmp_time.sec == 0 && tmp_time.usec == 0)
+               continue;
+           sfs_gettime(&curr_time);
+           SUBTIME(tmp_time, curr_time);
+           (void) biod_poll_wait(NFS_client,
+                                       tmp_time.sec * 1000000 + tmp_time.usec);
+       }
+    } /* while not done */
+
+    /*
+     * If we have not gotten an error and we were asked for an async write
+     * send a commit operation.
+     */  
+    if (ret && stab_flag != FILE_SYNC)
+       ret += (*Ops[COMMIT].funct)();
+
+    return (ret);
+
+} /* op_biod_write */
+
+
+/*
+ * perform an RPC read operation of length 'xfer_size'
+ */
+static int
+op_biod_read(
+    int                        xfer_size)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int                                max_cnt;        /* packet ctrs */
+    char                       buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
+    readargs                   args2;
+    readres                    reply2;         /* the reply */
+    READ3args                  args3;
+    READ3res                   reply3;         /* the reply */
+    int                                size;
+    struct ladtime             curr_time;
+    struct ladtime             call_timeout;
+    struct ladtime             tmp_time;
+    struct biod_req            *reqp;
+    int                                ret;            /* ret val == call success */
+    int                                num_out_reqs;   /* # of outstanding writes */
+    int                                i;
+    int                                error;
+    int32_t                    offset;
+    static int         calls = 0;
+
+    calls++;
+
+    if (nfs_version != NFS_VERSION && nfs_version != NFS_V3)
+       return (0);
+
+    op_ptr = &Ops[READ];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args2.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args3.file, (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /*
+     * Don't allow a read of less than one block size
+     */
+    if (xfer_size < Bytes_per_block)
+        xfer_size = Bytes_per_block;
+
+    /* Calculate the number of NFS reads required */
+    max_cnt = xfer_size / Bytes_per_block;
+    if ((xfer_size % Bytes_per_block) != 0) {
+           max_cnt++;
+    }
+
+    /* check our stats to see if this would overflow */
+    if (!Timed_run) {
+       if (op_ptr->target_calls > 0 &&
+           (op_ptr->results.good_calls + max_cnt) > op_ptr->target_calls) {
+           max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+       }
+    }
+
+    args2.offset = 0;
+    args3.offset._p._l = args3.offset._p._u = 0;
+
+    /*
+     * randomly choose an offset that is a multiple of the block size
+     * and constrained by making the transfer fit within the file
+     */
+    if (fh_size(Cur_file_ptr) > xfer_size) {
+       offset = Bytes_per_block * (sfs_random() %
+                           (((fh_size(Cur_file_ptr) - xfer_size)
+                           / Bytes_per_block) + 1));
+       args2.offset = offset;
+       args3.offset._p._u = 0;
+       args3.offset._p._l = offset;
+    }
+
+    size = Bytes_per_block;
+    args2.count = size;
+    args3.count = size;
+    args2.totalcount = size;   /* unused */
+
+    /* Have lower layers fill in the data directly.  */
+    reply2.readres_u.reply.data.data_val = buf;
+    reply3.res_u.ok.data.data_val = buf;
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "read: %d buffers xfer_size %d\n",
+                         max_cnt, xfer_size);
+       (void) fflush(stderr);
+    }
+
+    /* Mark all request slots as not in use */
+    for (reqp = biod_reqp, i = 0; i < max_biod_reqs; i++, reqp++) {
+       reqp->in_use = FALSE;
+    }
+
+    if (Current_test_phase < Warmup_phase) {
+       call_timeout.sec = Nfs_timers[Init].tv_sec;
+       call_timeout.usec = Nfs_timers[Init].tv_usec;
+    } else {
+       call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+    }
+
+    /* capture length for possible dump */
+    Dump_length = fh_size(Cur_file_ptr);
+
+    /* make the call(s) now */
+    num_out_reqs = 0;
+    while (xfer_size > 0 || num_out_reqs > 0) {
+       /*
+        * Send out calls async until either the maximum number of outstanding
+        * requests has been reached or there are no more requests to make.
+        */
+       while (num_out_reqs < max_out_reads && xfer_size > 0) {
+
+           /* find an empty read request slot */
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   break;
+               }
+           }
+
+           if (xfer_size < size) {
+               size = xfer_size;
+               args2.count = xfer_size;
+               args3.count = xfer_size;
+               args2.totalcount = xfer_size;           /* unused */
+           }
+           xfer_size -= size;
+
+           sfs_gettime(&reqp->start);
+           if (nfs_version == NFS_VERSION) {
+               reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC_READ,
+                                       xdr_read, (char *) &args2);
+               if (reqp->xid != 0) {
+                   /* capture count and offset for possible dump */
+                   reqp->count = args2.count;
+                   reqp->offset = args2.offset;
+                   reqp->timeout = reqp->start;
+                   ADDTIME(reqp->timeout, call_timeout);
+                   reqp->in_use = TRUE;
+                   num_out_reqs++;
+               }
+           } else if (nfs_version == NFS_V3) {
+               reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC3_READ,
+                                       xdr_READ3args, (char *) &args3);
+               if (reqp->xid != 0) {
+                   /* capture count and offset for possible dump */
+                   reqp->count = args3.count;
+                   reqp->offset = args3.offset._p._l;
+                   reqp->timeout = reqp->start;
+                   ADDTIME(reqp->timeout, call_timeout);
+                   reqp->in_use = TRUE;
+                   num_out_reqs++;
+               }
+           }
+
+           args2.offset += size;
+           args3.offset._p._l += size;
+           if (biod_poll_wait(NFS_client, 0) > 0) {
+               break;
+           }
+       } /* while can make an async call */
+
+       /*
+        * Process replies while there is data on the socket buffer.
+        * Just do polls on the select, no sleeping occurs in this loop.
+        */
+       do {
+           error = biod_poll_wait(NFS_client, 0);
+           switch (error) {
+               case -1:
+                   if (errno == EINTR) {
+                       error = 1;
+                       continue;
+                   }
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf(stderr,
+                                       "%s:[%d]: biod_poll_wait error\n",
+                                       sfs_Myname, calls);
+                       (void) fflush(stderr);
+                   }
+                   break;
+
+               case 0:
+                   break;
+
+
+               default:
+                   if (nfs_version == NFS_VERSION)
+                       reqp = biod_get_reply(NFS_client, xdr_read,
+                                         (char *) &reply2,
+                                         &Nfs_timers[op_ptr->call_class]);
+                   if (nfs_version == NFS_V3)
+                       reqp = biod_get_reply(NFS_client, xdr_READ3res,
+                                         (char *) &reply3,
+                                         &Nfs_timers[op_ptr->call_class]);
+
+                   /*
+                    * If biod_get_reply returns NULL then we got an RPC
+                    * level error, probably a dropped fragment or the
+                    * remains of a previous partial request.
+                    */
+                   if (reqp == (struct biod_req *)NULL) {
+                       error = 0;
+                       break;
+                   }
+
+                   /*
+                    * We have a valid response, check if procedure completed
+                    * correctly.
+                    */
+                   if ((nfs_version == NFS_VERSION &&
+                                               reply2.status == NFS_OK) ||
+                        (nfs_version == NFS_V3 &&
+                                               reply3.status == NFS3_OK)) {
+                       Cur_file_ptr->state = Exists;
+                       if (DEBUG_CHILD_RPC) {
+                           (void) fprintf(stderr, "%s: READ %s %d bytes offset %d\n",
+                                  sfs_Myname, Cur_filename, reqp->count, reqp->offset);
+                           (void) fflush(stderr);
+                       }
+                       /*
+                        * In updating attributes we may get replies out
+                        * of order.  We blindly update the attributes
+                        * which may cause old attributes to be stored.
+                        * XXX We should check for old attributes.
+                        */
+                       if (nfs_version == NFS_VERSION) {
+                           Cur_file_ptr->attributes2 =
+                                       reply2.readres_u.reply.attributes;
+                           /* capture count and offset for possible dump */
+                           Dump_count = reply2.readres_u.reply.data.data_len;
+                       }
+                       if (nfs_version == NFS_V3) {
+                           Cur_file_ptr->attributes3 =
+                                       reply3.res_u.ok.file_attributes.attr;
+                           /* capture count and offset for possible dump */
+                           Dump_count = reply3.res_u.ok.data.data_len;
+                       }
+
+                       Dump_offset = reqp->offset;
+                       sfs_elapsedtime(op_ptr, &reqp->start, &reqp->stop);
+                       op_ptr->results.good_calls++;
+                       Ops[TOTAL].results.good_calls++;
+                       ret++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                   } else {
+                       op_ptr->results.bad_calls++;
+                       Ops[TOTAL].results.bad_calls++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf(stderr,
+                                   "[%d]:BIOD READ FAILED: xid %x",
+                                   calls, reqp->xid);
+
+                           if (nfs_version == NFS_VERSION)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply2.status);
+                           if (nfs_version == NFS_V3)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply3.status);
+                           (void) fprintf(stderr, "\n");
+                       }
+                   }
+                   break;
+           } /* switch */
+       } while (error > 0 && num_out_reqs > 0);
+
+       /* Scan for replies that have timed out */
+       if (num_out_reqs > 0) {
+           sfs_gettime(&curr_time);
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (reqp->timeout.sec < curr_time.sec ||
+                   (reqp->timeout.sec == curr_time.sec &&
+                    reqp->timeout.usec < curr_time.usec)) {
+
+                   op_ptr->results.bad_calls++;
+                   Ops[TOTAL].results.bad_calls++;
+                   reqp->in_use = FALSE;
+                   num_out_reqs--;
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf (stderr,
+"[%d]:Biod read timed out %x (%d.%06d) now (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               curr_time.sec, curr_time.usec);
+                       if (biod_poll_wait(NFS_client, 0) > 0) {
+                          (void) fprintf(stderr,
+                               "[%d]:BIOD READ TIMEOUT - data on input queue!\n", calls);
+                       }
+                   }
+               }
+           }
+       }
+
+       /*
+        * We go to sleep waiting for a reply if all the requests have
+        * been sent and there are outstanding requests, or we cannot
+        * send any more requests.
+        */
+       if ((xfer_size <= 0 && num_out_reqs > 0) ||
+           num_out_reqs == max_out_reads) {
+           /*
+            * Find the next outstanding request that will timeout
+            * and take a time differential to use for the poll timeout.
+            * If the differential is less than zero, then we go to the
+            * top of the loop. Note that we are not picky on errors
+            * returned by select, after the sleep we return to the top
+            * of the loop so extensive error/status checking is not
+            * needed.
+            */
+           tmp_time.sec = 0;
+           tmp_time.usec = 0;
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (tmp_time.sec == 0 ||
+                   (reqp->timeout.sec < tmp_time.sec ||
+                    (reqp->timeout.sec == tmp_time.sec &&
+                     reqp->timeout.usec < tmp_time.usec))) {
+                   
+                    tmp_time = reqp->timeout;
+               }
+           }
+           if (tmp_time.sec == 0 && tmp_time.usec == 0)
+               continue;
+           sfs_gettime(&curr_time);
+           SUBTIME(tmp_time, curr_time);
+           (void) biod_poll_wait(NFS_client,
+                                       tmp_time.sec * 1000000 + tmp_time.usec);
+       }
+    } /* while not done */
+
+    return(ret);
+
+} /* op_biod_read */
+
+#endif
+
+/*
+ * ----------------------  Async RPC Support Routines  ----------------------
+ */
+
+/*
+ * biod_clnt_call()
+ *
+ * Returns XID indicating success, 0 indicating failure.
+ */
+uint32_t
+biod_clnt_call(
+    CLIENT             *clnt_handlep,
+    uint32_t           proc,
+    xdrproc_t          xargs,
+    void               *argsp)
+{
+    struct timeval timeout;
+    uint32_t xid;
+
+    /*
+     * Set timeouts to be zero to force message passing semantics.
+     */
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    if ((clnt_call(clnt_handlep, proc, xargs, argsp, NULL,
+                                       &xid, timeout)) != RPC_TIMEDOUT) {
+       clnt_perror(clnt_handlep, "biod_clnt_call failed");
+       return (0);
+    }
+
+    return (xid);
+} /* biod_clnt_call */
+
+
+/*
+ * biod_get_reply()
+ *
+ * Returns pointer to the biod_req struct entry that a reply was received
+ * for.  Returns NULL if an error was detected.
+ * NOTES:
+ * 1) This routine should only be called when it is known that there is
+ *    data waiting on the socket.
+ */
+static struct biod_req *
+biod_get_reply(
+    CLIENT             *clnt_handlep,
+    xdrproc_t          xresults,
+    void               *resultsp,
+    struct timeval     *tv)
+{
+    uint32_t           xid;
+    int                        i;
+    int                        cnt = 0;
+    bool_t             res;
+    uint32_t           xids[MAX_BIODS];
+
+    /*
+     * Load list of valid outstanding xids
+     */
+    for (i = 0; i < max_biod_reqs; i++) {
+        if (biod_reqp[i].in_use == TRUE)
+           xids[cnt++] = biod_reqp[i].xid;
+    }
+
+    if (cnt == 0)
+       return (NULL);
+
+    if ((res = clnt_getreply(clnt_handlep, xresults,
+                       resultsp, cnt, xids, &xid, tv)) != RPC_SUCCESS) {
+       if (DEBUG_CHILD_BIOD) {
+               if (res == RPC_CANTDECODERES) {
+                       (void) fprintf(stderr, "No xid matched, found %x\n",
+                               xid);
+               }
+       }
+       return (NULL);
+    }
+
+    /*
+     * Scan to find XID matched in the outstanding request queue.
+     */
+    for (i = 0; i < max_biod_reqs; i++) {
+        if (biod_reqp[i].in_use == TRUE && biod_reqp[i].xid == xid) {
+           sfs_gettime(&(biod_reqp[i].stop));
+           return (&biod_reqp[i]);
+        }
+    }
+
+    return ((struct biod_req *)0);
+} /* biod_get_reply */
+
+/*
+ * biod_poll_wait()
+ *
+ * Returns -1 on error, 0 for no data available, > 0 to indicate data available
+ */
+int
+biod_poll_wait(
+    CLIENT             *clnt_handlep,
+    uint32_t           usecs)
+{
+    return (clnt_poll(clnt_handlep, usecs));
+} /* biod_poll_wait */
+
diff --git a/TBBT/trace_play/sfs_c_bio.org b/TBBT/trace_play/sfs_c_bio.org
new file mode 100644 (file)
index 0000000..88c54f5
--- /dev/null
@@ -0,0 +1,1012 @@
+#ifndef lint
+static char sfs_c_bioSid[] = "@(#)sfs_c_bio.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * ---------------------- sfs_c_bio.c ---------------------
+ *
+ *     Routines that attempt to simulate biod behavior
+ *
+ *     The routines contained here model biod behavior.  Simply call
+ *     biod_init() to replace regular calls to op_read() and op_write()
+ *     with calls to op_biod_read() and op_biod_write().  The variables
+ *     max_out_writes and max_out_reads control the maximum number of
+ *     outstanding writes and reads respectively.
+ *
+ *.Exported Routines
+ *     int     biod_init(int, int);
+ *     void    biod_turn_on(void);
+ *     void    op_biod_write(int, int, int);
+ *     void    op_biod_read(int);
+ *
+ *.Local Routines
+ *     uint32_t        biod_clnt_call(CLIENT *, uint32_t,
+ *                                             xdrproc_t, void *);
+ *     struct biod_req *biod_get_reply(CLIENT *, xdrproc_t,
+ *                                             void *, struct timeval *);
+ *     int             biod_poll_wait(CLIENT *, uint32_t);
+ *
+ *.Revision_History
+ *     03-May-94       Robinson
+ *                             History now kept in SCCS
+ *     03-Mar-92       0.1.0 Corbin
+ *                                     Added biod behavior
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+/*
+ * Information associated with outstanding read/write requests
+ */
+struct biod_req {
+    uint32_t           xid;            /* RPC transmission ID  */
+    bool_t             in_use;         /* Indicates if the entry is in use */
+    unsigned int       count;          /* Count saved for Dump routines */
+    unsigned int       offset;         /* Offset saved for Dump routines */
+    struct ladtime     start;          /* Time RPC call was made */
+    struct ladtime     stop;           /* Time RPC reply was received */
+    struct ladtime     timeout;        /* Time RPC call will time out */
+};
+
+/*
+ * ----------------------  Static Declarations  ----------------------
+ */
+
+static int     max_out_writes;
+static int     max_out_reads;
+static int     max_biod_reqs = 0;
+static struct biod_req *biod_reqp;
+
+/* forward definitions for local functions */
+static uint32_t        biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+static struct biod_req *biod_get_reply(CLIENT *, xdrproc_t,
+                                               void *, struct timeval *);
+static int     biod_poll_wait(CLIENT *, uint32_t);
+
+static int op_biod_write(int, int, int);
+static int op_biod_read(int);
+
+/*
+ * ----------------------  BIOD Support Routines  ----------------------
+ */
+
+/*
+ * biod_init()
+ *
+ * This function is called during the initialization phase. It performs
+ * the following tasks:
+ *     - Allocate memory to hold outstanding biod request information
+ *
+ * Returns 0 for OK, -1 for failure
+ */
+int
+biod_init(
+    int                        out_writes,
+    int                        out_reads)
+{
+    max_out_writes = MAXIMUM(1, out_writes);
+    max_out_reads = MAXIMUM(1, out_reads);
+    max_biod_reqs = MAXIMUM(out_writes, out_reads);
+
+    biod_reqp = (struct biod_req *) calloc(max_biod_reqs,
+                                          sizeof (struct biod_req));
+    if (biod_reqp == (struct biod_req *)0) {
+       (void) fprintf(stderr, "%s: biod_init calloc failed.\n", sfs_Myname);
+       (void) fflush(stderr);
+       return (-1);
+    }
+
+    return (0);
+} /* biod_init */
+
+
+/*
+ *     - Change the operation functions for reads and writes to use the
+ *       biod routines. This step should be done last to allow callers
+ *       to still run with the old op functions if the biod initialization
+ *       fails.
+ */
+void
+biod_turn_on(void)
+{
+    Ops[WRITE].funct = op_biod_write;
+    Ops[READ].funct = op_biod_read;
+}
+
+/*
+ * biod_term()
+ *
+ * This function is called during the termination phase to free any resources
+ * allocated by the biod_init() routine. It performs the following tasks:
+ *     - Frees memory associated with outstanding biod request information
+ *     - Frees the biod client handle
+ */
+void
+biod_term(void)
+{
+    if (max_biod_reqs) {
+       free(biod_reqp);
+    }
+} /* biod_term */
+
+/*
+ * Perform and RPC biod style write operation of length 'xfer_size'.
+ * If 'append_flag' is true, then write the data to the end of the file.
+ */
+static int
+op_biod_write(
+    int                        xfer_size,
+    int                        append_flag,
+    int                        stab_flag)
+{
+    sfs_op_type                *op_ptr;        /* per operation info */
+    static char                *buf = NULL;    /* the data buffer */
+    unsigned int       size;           /* size of data write */
+    int                        max_cnt;
+    attrstat           reply2;         /* the reply */
+    writeargs          args2;
+    WRITE3res          reply3;         /* the reply */
+    WRITE3args         args3;
+    struct ladtime     curr_time;
+    struct ladtime     tmp_time;
+    struct ladtime     call_timeout;
+    struct biod_req    *reqp;
+    int                        ret;            /* ret val == call success */
+    int                        num_out_reqs;   /* # of outstanding writes */
+    int                        i;
+    int                        error;
+    int32_t            offset;
+    static int         calls = 0;
+
+    calls++;
+
+    if (nfs_version != NFS_VERSION && nfs_version != NFS_V3)
+       return (0);
+
+    /*
+     * Initialize write buffer to known value
+     */  
+    if (buf == NULL) {
+        buf = init_write_buffer();
+    }
+
+
+    /*
+     * For now we treat DATA_SYNC to be the same as FILE_SYNC.
+     * If it is not a V3 op then it must always be stable
+     */  
+    if (stab_flag == DATA_SYNC || nfs_version != NFS_V3)
+        stab_flag = FILE_SYNC;
+
+    op_ptr = &Ops[WRITE];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args2.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args3.file, (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    args2.beginoffset = 0;     /* unused */
+
+    if (append_flag == 1) {
+       args2.offset = Cur_file_ptr->attributes2.size;
+       args3.offset = Cur_file_ptr->attributes3.size;
+    } else {
+       if (fh_size(Cur_file_ptr) > xfer_size) {
+           offset = Bytes_per_block * (sfs_random() %
+                           (((fh_size(Cur_file_ptr) - xfer_size)
+                           / Bytes_per_block) + 1));
+           args2.offset = offset;
+           args3.offset._p._u = 0;
+           args3.offset._p._l = offset;
+       } else {
+           args2.offset = 0;
+           args3.offset._p._u = args3.offset._p._l = 0;
+       }
+    }
+
+    size = Bytes_per_block;
+    args2.totalcount = size;   /* unused */
+    args2.data.data_len = size;
+    args2.data.data_val = buf;
+    args3.data.data_len = size;
+    args3.data.data_val = buf;
+    args3.count = size;
+    args3.stable = stab_flag;
+
+    /* Calculate the number of NFS writes required */
+    max_cnt = xfer_size / Bytes_per_block;
+    if ((xfer_size % Bytes_per_block) != 0) {
+       max_cnt++;
+    }
+
+    /* check our stats to see if this would overflow */
+    if (!Timed_run) {
+       if (op_ptr->target_calls > 0 &&
+          (op_ptr->results.good_calls + max_cnt) > op_ptr->target_calls) {
+           max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+       }
+    }
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "write: %d buffers xfer_size %d\n",
+                         max_cnt, xfer_size);
+       (void) fflush(stderr);
+    }
+
+    /* Mark all request slots as not in use */
+    for (reqp = biod_reqp, i = 0; i < max_biod_reqs; i++, reqp++) {
+       reqp->in_use = FALSE;
+    }
+
+    if (Current_test_phase < Warmup_phase) {
+       call_timeout.sec = Nfs_timers[Init].tv_sec;
+       call_timeout.usec = Nfs_timers[Init].tv_usec;
+    } else {
+       call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+    }
+
+    /* capture length for possible dump */
+    Dump_length = fh_size(Cur_file_ptr);
+    /* make the call(s) now */
+    num_out_reqs = 0;
+    while (xfer_size > 0 || num_out_reqs > 0) {
+       /*
+        * Send out calls async until either the maximum number of outstanding
+        * requests has been reached or there are no more requests to make.
+        */
+       while (num_out_reqs < max_out_writes && xfer_size > 0) {
+
+           /* find an empty write request slot */
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   break;
+               }
+           }
+
+           if (xfer_size < size) {
+               size = xfer_size;
+               args2.data.data_len = xfer_size;
+               args2.totalcount = xfer_size;           /* unused */
+               args3.data.data_len = xfer_size;
+               args3.count = xfer_size;
+           }
+           xfer_size -= size;
+
+           sfs_gettime(&reqp->start);
+           if (nfs_version == NFS_V3) {
+                   reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC3_WRITE,
+                                       xdr_WRITE3args, (char *) &args3);
+                   if (reqp->xid != 0) {
+                       /* capture count and offset for possible dump */
+                       reqp->count = args3.data.data_len;
+                       reqp->offset = args3.offset._p._l;
+                       reqp->timeout = reqp->start;
+                       ADDTIME(reqp->timeout, call_timeout);
+                       reqp->in_use = TRUE;
+                       num_out_reqs++;
+                   }
+           }
+           if (nfs_version == NFS_VERSION) {
+                   reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC_WRITE,
+                                       xdr_write, (char *) &args2);
+                   if (reqp->xid != 0) {
+                       /* capture count and offset for possible dump */
+                       reqp->count = args2.data.data_len;
+                       reqp->offset = args2.offset;
+                       reqp->timeout = reqp->start;
+                       ADDTIME(reqp->timeout, call_timeout);
+                       reqp->in_use = TRUE;
+                       num_out_reqs++;
+                   }
+           }
+           if (DEBUG_CHILD_BIOD) {
+               (void) fprintf (stderr,
+"[%d]:Biod write started xid %x start (%d.%06d) timeo (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec);
+           }
+
+           args2.offset += size;
+           args3.offset._p._l += size;
+           if (biod_poll_wait(NFS_client, 0) > 0) {
+               break;
+           }
+       } /* while can make an async call */
+
+       /*
+        * Process replies while there is data on the socket buffer.
+        * Just do polls on the select, no sleeping occurs in this loop.
+        */
+       do {
+           error = biod_poll_wait(NFS_client, 0);
+           switch (error) {
+               case -1:
+                   if (errno == EINTR) {
+                       error = 1;
+                       continue;
+                   }
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf(stderr, "%s:[%d]: biod_poll_wait error\n",
+                                          sfs_Myname, calls);
+                       (void) fflush(stderr);
+                   }
+                   break;
+
+               case 0:
+                   break;
+
+
+               default:
+                   if (nfs_version == NFS_VERSION)
+                           reqp = biod_get_reply(NFS_client, xdr_write,
+                                         (char *) &reply2,
+                                         &Nfs_timers[op_ptr->call_class]);
+                   if (nfs_version == NFS_V3)
+                           reqp = biod_get_reply(NFS_client, xdr_WRITE3res,
+                                         (char *) &reply3,
+                                         &Nfs_timers[op_ptr->call_class]);
+
+                   /*
+                    * If biod_get_reply returns NULL then we got an RPC
+                    * level error, probably a dropped fragment or the
+                    * remains of a previous partial request.
+                    */
+                   if (reqp == (struct biod_req *)NULL) {
+                       error = 0;
+                       break;
+                   }
+
+                   /*
+                    * We have a valid response, check if procedure completed
+                    * correctly.
+                    */
+                   if ((nfs_version == NFS_VERSION &&
+                        reply2.status == NFS_OK) ||
+                        (nfs_version == NFS_V3 && reply3.status == NFS3_OK)) {
+                       Cur_file_ptr->state = Exists;
+                       /*
+                        * In updating attributes we may get replies out
+                        * of order.  We blindly update the attributes
+                        * which may cause old attributes to be stored.
+                        * XXX We should check for old attributes.
+                        */
+                       if (nfs_version == NFS_VERSION)
+                           Cur_file_ptr->attributes2 =
+                                       reply2.attrstat_u.attributes;
+                       if (nfs_version == NFS_V3)
+                           Cur_file_ptr->attributes3 =
+                                       reply3.res_u.ok.file_wcc.after.attr;
+                       if (DEBUG_CHILD_RPC) {
+                           (void) fprintf(stderr,
+                                       "%s: WRITE %s %d bytes offset %d \n",
+                                       sfs_Myname, Cur_filename,
+                                       reqp->count, reqp->offset);
+                           (void) fflush(stderr);
+                       }
+
+                       /* capture count and offset for possible dump */
+                       Dump_count = reqp->count;
+                       Dump_offset = reqp->offset;
+                       sfs_elapsedtime(op_ptr, &reqp->start, &reqp->stop);
+                       op_ptr->results.good_calls++;
+                       Ops[TOTAL].results.good_calls++;
+                       ret++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf (stderr,
+"[%d]:Biod write succeded xid %x start (%d.%06d) timeo (%d.%06d) stop (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               reqp->stop.sec, reqp->stop.usec);
+                       }
+                   } else {
+                       op_ptr->results.bad_calls++;
+                       Ops[TOTAL].results.bad_calls++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf (stderr,
+"[%d]:Biod write failed xid %x start (%d.%06d) timeo (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec);
+
+                           (void) fprintf(stderr,
+                                   "[%d]:BIOD WRITE FAILED: xid %x",
+                                   calls, reqp->xid);
+
+                           if (nfs_version == NFS_VERSION)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply2.status);
+                           if (nfs_version == NFS_V3)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply3.status);
+                           (void) fprintf(stderr, "\n");
+                       }
+                   }
+                   break;
+           }
+       } while (error > 0 && num_out_reqs > 0);
+
+       /* Scan for replies that have timed out */
+       if (num_out_reqs > 0) {
+           sfs_gettime(&curr_time);
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (reqp->timeout.sec < curr_time.sec ||
+                   (reqp->timeout.sec == curr_time.sec &&
+                   reqp->timeout.usec < curr_time.usec)) {
+
+                   op_ptr->results.bad_calls++;
+                   Ops[TOTAL].results.bad_calls++;
+                   reqp->in_use = FALSE;
+                   num_out_reqs--;
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf (stderr,
+"[%d]:Biod write timed out %x start (%d.%06d) timeo (%d.%06d) now (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->start.sec, reqp->start.usec,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               curr_time.sec, curr_time.usec);
+                       if (biod_poll_wait(NFS_client, 0) > 0) {
+                          (void) fprintf(stderr,
+                               "[%d]:BIOD WRITE TIMEOUT - data on input queue!\n", calls);
+                       }
+                   }
+               }
+           }
+       }
+
+       /*
+        * We go to sleep waiting for a reply if all the requests have
+        * been sent and there are outstanding requests, or we cannot
+        * send any more requests.
+        */
+       if ((xfer_size <= 0 && num_out_reqs > 0) ||
+           num_out_reqs == max_out_writes) {
+           /*
+            * Find the next outstanding request that will timeout
+            * and take a time differential to use for the poll timeout.
+            * If the differential is less than zero, then we go to the
+            * top of the loop. Note that we are not picky on errors
+            * returned by select, after the sleep we return to the top
+            * of the loop so extensive error/status checking is not
+            * needed.
+            */
+           tmp_time.sec = 0;
+           tmp_time.usec = 0;
+           for (reqp = biod_reqp, i = 0; i < max_out_writes; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (tmp_time.sec == 0 ||
+                   (reqp->timeout.sec < tmp_time.sec ||
+                    (reqp->timeout.sec == tmp_time.sec &&
+                     reqp->timeout.usec < tmp_time.usec))) {
+                   
+                    tmp_time = reqp->timeout;
+               }
+           }
+           if (tmp_time.sec == 0 && tmp_time.usec == 0)
+               continue;
+           sfs_gettime(&curr_time);
+           SUBTIME(tmp_time, curr_time);
+           (void) biod_poll_wait(NFS_client,
+                                       tmp_time.sec * 1000000 + tmp_time.usec);
+       }
+    } /* while not done */
+
+    /*
+     * If we have not gotten an error and we were asked for an async write
+     * send a commit operation.
+     */  
+    if (ret && stab_flag != FILE_SYNC)
+       ret += (*Ops[COMMIT].funct)();
+
+    return (ret);
+
+} /* op_biod_write */
+
+
+/*
+ * perform an RPC read operation of length 'xfer_size'
+ */
+static int
+op_biod_read(
+    int                        xfer_size)
+{
+    sfs_op_type                        *op_ptr;        /* per operation info */
+    int                                max_cnt;        /* packet ctrs */
+    char                       buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
+    readargs                   args2;
+    readres                    reply2;         /* the reply */
+    READ3args                  args3;
+    READ3res                   reply3;         /* the reply */
+    int                                size;
+    struct ladtime             curr_time;
+    struct ladtime             call_timeout;
+    struct ladtime             tmp_time;
+    struct biod_req            *reqp;
+    int                                ret;            /* ret val == call success */
+    int                                num_out_reqs;   /* # of outstanding writes */
+    int                                i;
+    int                                error;
+    int32_t                    offset;
+    static int         calls = 0;
+
+    calls++;
+
+    if (nfs_version != NFS_VERSION && nfs_version != NFS_V3)
+       return (0);
+
+    op_ptr = &Ops[READ];
+    ret = 0;
+
+    /* set up the arguments */
+    (void) memmove((char *) &args2.file, (char *) &Cur_file_ptr->fh2,
+                       NFS_FHSIZE);
+    (void) memmove((char *) &args3.file, (char *) &Cur_file_ptr->fh3,
+                       sizeof (nfs_fh3));
+
+    /*
+     * Don't allow a read of less than one block size
+     */
+    if (xfer_size < Bytes_per_block)
+        xfer_size = Bytes_per_block;
+
+    /* Calculate the number of NFS reads required */
+    max_cnt = xfer_size / Bytes_per_block;
+    if ((xfer_size % Bytes_per_block) != 0) {
+           max_cnt++;
+    }
+
+    /* check our stats to see if this would overflow */
+    if (!Timed_run) {
+       if (op_ptr->target_calls > 0 &&
+           (op_ptr->results.good_calls + max_cnt) > op_ptr->target_calls) {
+           max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
+       }
+    }
+
+    args2.offset = 0;
+    args3.offset._p._l = args3.offset._p._u = 0;
+
+    /*
+     * randomly choose an offset that is a multiple of the block size
+     * and constrained by making the transfer fit within the file
+     */
+    if (fh_size(Cur_file_ptr) > xfer_size) {
+       offset = Bytes_per_block * (sfs_random() %
+                           (((fh_size(Cur_file_ptr) - xfer_size)
+                           / Bytes_per_block) + 1));
+       args2.offset = offset;
+       args3.offset._p._u = 0;
+       args3.offset._p._l = offset;
+    }
+
+    size = Bytes_per_block;
+    args2.count = size;
+    args3.count = size;
+    args2.totalcount = size;   /* unused */
+
+    /* Have lower layers fill in the data directly.  */
+    reply2.readres_u.reply.data.data_val = buf;
+    reply3.res_u.ok.data.data_val = buf;
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "read: %d buffers xfer_size %d\n",
+                         max_cnt, xfer_size);
+       (void) fflush(stderr);
+    }
+
+    /* Mark all request slots as not in use */
+    for (reqp = biod_reqp, i = 0; i < max_biod_reqs; i++, reqp++) {
+       reqp->in_use = FALSE;
+    }
+
+    if (Current_test_phase < Warmup_phase) {
+       call_timeout.sec = Nfs_timers[Init].tv_sec;
+       call_timeout.usec = Nfs_timers[Init].tv_usec;
+    } else {
+       call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+    }
+
+    /* capture length for possible dump */
+    Dump_length = fh_size(Cur_file_ptr);
+
+    /* make the call(s) now */
+    num_out_reqs = 0;
+    while (xfer_size > 0 || num_out_reqs > 0) {
+       /*
+        * Send out calls async until either the maximum number of outstanding
+        * requests has been reached or there are no more requests to make.
+        */
+       while (num_out_reqs < max_out_reads && xfer_size > 0) {
+
+           /* find an empty read request slot */
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   break;
+               }
+           }
+
+           if (xfer_size < size) {
+               size = xfer_size;
+               args2.count = xfer_size;
+               args3.count = xfer_size;
+               args2.totalcount = xfer_size;           /* unused */
+           }
+           xfer_size -= size;
+
+           sfs_gettime(&reqp->start);
+           if (nfs_version == NFS_VERSION) {
+               reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC_READ,
+                                       xdr_read, (char *) &args2);
+               if (reqp->xid != 0) {
+                   /* capture count and offset for possible dump */
+                   reqp->count = args2.count;
+                   reqp->offset = args2.offset;
+                   reqp->timeout = reqp->start;
+                   ADDTIME(reqp->timeout, call_timeout);
+                   reqp->in_use = TRUE;
+                   num_out_reqs++;
+               }
+           } else if (nfs_version == NFS_V3) {
+               reqp->xid = biod_clnt_call(NFS_client,
+                                       (uint32_t)NFSPROC3_READ,
+                                       xdr_READ3args, (char *) &args3);
+               if (reqp->xid != 0) {
+                   /* capture count and offset for possible dump */
+                   reqp->count = args3.count;
+                   reqp->offset = args3.offset._p._l;
+                   reqp->timeout = reqp->start;
+                   ADDTIME(reqp->timeout, call_timeout);
+                   reqp->in_use = TRUE;
+                   num_out_reqs++;
+               }
+           }
+
+           args2.offset += size;
+           args3.offset._p._l += size;
+           if (biod_poll_wait(NFS_client, 0) > 0) {
+               break;
+           }
+       } /* while can make an async call */
+
+       /*
+        * Process replies while there is data on the socket buffer.
+        * Just do polls on the select, no sleeping occurs in this loop.
+        */
+       do {
+           error = biod_poll_wait(NFS_client, 0);
+           switch (error) {
+               case -1:
+                   if (errno == EINTR) {
+                       error = 1;
+                       continue;
+                   }
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf(stderr,
+                                       "%s:[%d]: biod_poll_wait error\n",
+                                       sfs_Myname, calls);
+                       (void) fflush(stderr);
+                   }
+                   break;
+
+               case 0:
+                   break;
+
+
+               default:
+                   if (nfs_version == NFS_VERSION)
+                       reqp = biod_get_reply(NFS_client, xdr_read,
+                                         (char *) &reply2,
+                                         &Nfs_timers[op_ptr->call_class]);
+                   if (nfs_version == NFS_V3)
+                       reqp = biod_get_reply(NFS_client, xdr_READ3res,
+                                         (char *) &reply3,
+                                         &Nfs_timers[op_ptr->call_class]);
+
+                   /*
+                    * If biod_get_reply returns NULL then we got an RPC
+                    * level error, probably a dropped fragment or the
+                    * remains of a previous partial request.
+                    */
+                   if (reqp == (struct biod_req *)NULL) {
+                       error = 0;
+                       break;
+                   }
+
+                   /*
+                    * We have a valid response, check if procedure completed
+                    * correctly.
+                    */
+                   if ((nfs_version == NFS_VERSION &&
+                                               reply2.status == NFS_OK) ||
+                        (nfs_version == NFS_V3 &&
+                                               reply3.status == NFS3_OK)) {
+                       Cur_file_ptr->state = Exists;
+                       if (DEBUG_CHILD_RPC) {
+                           (void) fprintf(stderr, "%s: READ %s %d bytes offset %d\n",
+                                  sfs_Myname, Cur_filename, reqp->count, reqp->offset);
+                           (void) fflush(stderr);
+                       }
+                       /*
+                        * In updating attributes we may get replies out
+                        * of order.  We blindly update the attributes
+                        * which may cause old attributes to be stored.
+                        * XXX We should check for old attributes.
+                        */
+                       if (nfs_version == NFS_VERSION) {
+                           Cur_file_ptr->attributes2 =
+                                       reply2.readres_u.reply.attributes;
+                           /* capture count and offset for possible dump */
+                           Dump_count = reply2.readres_u.reply.data.data_len;
+                       }
+                       if (nfs_version == NFS_V3) {
+                           Cur_file_ptr->attributes3 =
+                                       reply3.res_u.ok.file_attributes.attr;
+                           /* capture count and offset for possible dump */
+                           Dump_count = reply3.res_u.ok.data.data_len;
+                       }
+
+                       Dump_offset = reqp->offset;
+                       sfs_elapsedtime(op_ptr, &reqp->start, &reqp->stop);
+                       op_ptr->results.good_calls++;
+                       Ops[TOTAL].results.good_calls++;
+                       ret++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+                   } else {
+                       op_ptr->results.bad_calls++;
+                       Ops[TOTAL].results.bad_calls++;
+                       reqp->in_use = FALSE;
+                       num_out_reqs--;
+
+                       if (DEBUG_CHILD_BIOD) {
+                           (void) fprintf(stderr,
+                                   "[%d]:BIOD READ FAILED: xid %x",
+                                   calls, reqp->xid);
+
+                           if (nfs_version == NFS_VERSION)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply2.status);
+                           if (nfs_version == NFS_V3)
+                               (void) fprintf(stderr, "  status %d",
+                                                               reply3.status);
+                           (void) fprintf(stderr, "\n");
+                       }
+                   }
+                   break;
+           } /* switch */
+       } while (error > 0 && num_out_reqs > 0);
+
+       /* Scan for replies that have timed out */
+       if (num_out_reqs > 0) {
+           sfs_gettime(&curr_time);
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (reqp->timeout.sec < curr_time.sec ||
+                   (reqp->timeout.sec == curr_time.sec &&
+                    reqp->timeout.usec < curr_time.usec)) {
+
+                   op_ptr->results.bad_calls++;
+                   Ops[TOTAL].results.bad_calls++;
+                   reqp->in_use = FALSE;
+                   num_out_reqs--;
+                   if (DEBUG_CHILD_BIOD) {
+                       (void) fprintf (stderr,
+"[%d]:Biod read timed out %x (%d.%06d) now (%d.%06d)\n",
+                               calls, reqp->xid,
+                               reqp->timeout.sec, reqp->timeout.usec,
+                               curr_time.sec, curr_time.usec);
+                       if (biod_poll_wait(NFS_client, 0) > 0) {
+                          (void) fprintf(stderr,
+                               "[%d]:BIOD READ TIMEOUT - data on input queue!\n", calls);
+                       }
+                   }
+               }
+           }
+       }
+
+       /*
+        * We go to sleep waiting for a reply if all the requests have
+        * been sent and there are outstanding requests, or we cannot
+        * send any more requests.
+        */
+       if ((xfer_size <= 0 && num_out_reqs > 0) ||
+           num_out_reqs == max_out_reads) {
+           /*
+            * Find the next outstanding request that will timeout
+            * and take a time differential to use for the poll timeout.
+            * If the differential is less than zero, then we go to the
+            * top of the loop. Note that we are not picky on errors
+            * returned by select, after the sleep we return to the top
+            * of the loop so extensive error/status checking is not
+            * needed.
+            */
+           tmp_time.sec = 0;
+           tmp_time.usec = 0;
+           for (reqp = biod_reqp, i = 0; i < max_out_reads; i++, reqp++) {
+               if (reqp->in_use == FALSE) {
+                   continue;
+               }
+               if (tmp_time.sec == 0 ||
+                   (reqp->timeout.sec < tmp_time.sec ||
+                    (reqp->timeout.sec == tmp_time.sec &&
+                     reqp->timeout.usec < tmp_time.usec))) {
+                   
+                    tmp_time = reqp->timeout;
+               }
+           }
+           if (tmp_time.sec == 0 && tmp_time.usec == 0)
+               continue;
+           sfs_gettime(&curr_time);
+           SUBTIME(tmp_time, curr_time);
+           (void) biod_poll_wait(NFS_client,
+                                       tmp_time.sec * 1000000 + tmp_time.usec);
+       }
+    } /* while not done */
+
+    return(ret);
+
+} /* op_biod_read */
+
+/*
+ * ----------------------  Async RPC Support Routines  ----------------------
+ */
+
+/*
+ * biod_clnt_call()
+ *
+ * Returns XID indicating success, 0 indicating failure.
+ */
+static uint32_t
+biod_clnt_call(
+    CLIENT             *clnt_handlep,
+    uint32_t           proc,
+    xdrproc_t          xargs,
+    void               *argsp)
+{
+    struct timeval timeout;
+    uint32_t xid;
+
+    /*
+     * Set timeouts to be zero to force message passing semantics.
+     */
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    if ((clnt_call(clnt_handlep, proc, xargs, argsp, NULL,
+                                       &xid, timeout)) != RPC_TIMEDOUT) {
+       clnt_perror(clnt_handlep, "biod_clnt_call failed");
+       return (0);
+    }
+
+    return (xid);
+} /* biod_clnt_call */
+
+
+/*
+ * biod_get_reply()
+ *
+ * Returns pointer to the biod_req struct entry that a reply was received
+ * for.  Returns NULL if an error was detected.
+ * NOTES:
+ * 1) This routine should only be called when it is known that there is
+ *    data waiting on the socket.
+ */
+static struct biod_req *
+biod_get_reply(
+    CLIENT             *clnt_handlep,
+    xdrproc_t          xresults,
+    void               *resultsp,
+    struct timeval     *tv)
+{
+    uint32_t           xid;
+    int                        i;
+    int                        cnt = 0;
+    bool_t             res;
+    uint32_t           xids[MAX_BIODS];
+
+    /*
+     * Load list of valid outstanding xids
+     */
+    for (i = 0; i < max_biod_reqs; i++) {
+        if (biod_reqp[i].in_use == TRUE)
+           xids[cnt++] = biod_reqp[i].xid;
+    }
+
+    if (cnt == 0)
+       return (NULL);
+
+    if ((res = clnt_getreply(clnt_handlep, xresults,
+                       resultsp, cnt, xids, &xid, tv)) != RPC_SUCCESS) {
+       if (DEBUG_CHILD_BIOD) {
+               if (res == RPC_CANTDECODERES) {
+                       (void) fprintf(stderr, "No xid matched, found %x\n",
+                               xid);
+               }
+       }
+       return (NULL);
+    }
+
+    /*
+     * Scan to find XID matched in the outstanding request queue.
+     */
+    for (i = 0; i < max_biod_reqs; i++) {
+        if (biod_reqp[i].in_use == TRUE && biod_reqp[i].xid == xid) {
+           sfs_gettime(&(biod_reqp[i].stop));
+           return (&biod_reqp[i]);
+        }
+    }
+
+    return ((struct biod_req *)0);
+} /* biod_get_reply */
+
+
+/*
+ * biod_poll_wait()
+ *
+ * Returns -1 on error, 0 for no data available, > 0 to indicate data available
+ */
+static int
+biod_poll_wait(
+    CLIENT             *clnt_handlep,
+    uint32_t           usecs)
+{
+    return (clnt_poll(clnt_handlep, usecs));
+} /* biod_poll_wait */
diff --git a/TBBT/trace_play/sfs_c_chd.2thread.c b/TBBT/trace_play/sfs_c_chd.2thread.c
new file mode 100644 (file)
index 0000000..48ab54e
--- /dev/null
@@ -0,0 +1,3509 @@
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static int read_trace(void);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+void adjust_play_window (int flag, int * poll_timeout);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern inline fh_map_t * lookup_fh (char * trace_fh );
+static inline void finish_request (int biod_index, int dep_index, int status);
+static inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+static inline char * find_lead_trace_fh(int proc, char * line);
+static inline char * find_reply_trace_fh (char * line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                       22, 19};
+void print_usage(int pos, int argc, char ** argv)
+{
+       int i;
+       printf("sfs3 hostname:mount_dir trace_file|stdin fh_map_file play_scale warmup_time(in seconds) \n");
+       printf("sfs3 -pair_trace trace_file\n");
+       printf("sfs3 -pair_write trace_file\n");
+       printf("sfs3 -help\n");
+       printf ("pos %d argc %d", pos, argc);
+       for (i=0; i<argc; i++) {
+               printf(" %s", argv[i]);
+       } 
+       printf ("\n");
+       exit;
+}
+
+void print_cyclic_buffers ()
+{
+       CYCLIC_PRINT(memory_trace_index);
+       CYCLIC_PRINT(dep_tab_index);
+       CYCLIC_PRINT(dep_window_index);
+}
+
+void add_to_dep_tab(int i)
+{
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       dep_tab_t * ent;
+
+    trace_fh = strstr (memory_trace[i].line, "fh");
+    if (!trace_fh)
+       printf ("memory_trace[%d].line %s\n", i, memory_trace[i].line);
+    RFS_ASSERT (trace_fh);
+    trace_fh += 3;
+    fh_map_entry = lookup_fh (trace_fh);
+    if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+        req_num_with_discard_fh ++;
+               return;
+       }
+    if (fh_map_entry)
+        req_num_with_init_fh ++;
+    else
+        req_num_with_new_fh ++;
+                                                                                                                              
+       RFS_ASSERT (!CYCLIC_FULL(dep_tab_index));
+       ent = &(dep_tab[dep_tab_index.head]);
+
+    ent->disk_index = memory_trace[i].disk_index;
+       ent->memory_index = i;
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+    ent->trace_status = memory_trace[i].trace_status;
+    ent->reply_trace_fh = memory_trace[i].reply_trace_fh;
+#endif
+    ent->line = memory_trace[i].line;
+    init_dep_tab_entry(dep_tab_index.head);
+
+    if (rfs_debug && (i%100000)==0)
+       printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_index.head, ent->disk_index, i, memory_trace[i].disk_index);
+    CYCLIC_MOVE_HEAD(memory_trace_index);
+    CYCLIC_MOVE_HEAD(dep_tab_index);
+}
+
+void init_profile_variables ()
+{
+       init_profile ("total_profile", &total_profile);
+       init_profile ("execute_next_request_profile", &execute_next_request_profile);
+       init_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       init_profile ("invalid_get_nextop_profile",&invalid_get_nextop_profile);
+       init_profile ("prepare_argument_profile", &prepare_argument_profile);
+       init_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       init_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       init_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       init_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       init_profile ("decode_reply_profile", &decode_reply_profile);
+       init_profile ("check_reply_profile", &check_reply_profile);
+       init_profile ("add_create_object_profile", &add_create_object_profile);
+       init_profile ("check_timeout_profile", &check_timeout_profile);
+       init_profile ("adjust_play_window_profile",&adjust_play_window_profile);
+       init_profile ("fgets_profile",&fgets_profile);
+       init_profile ("read_line_profile",&read_line_profile);
+       init_profile ("read_trace_profile",&read_trace_profile);
+}
+
+static char trace_file[256]="anon-lair62-011130-1200.txt";
+int print_memory_usage()
+{
+       printf("size of fh_map_t %d size of fh_map %d\n", sizeof(fh_map_t), sizeof(fh_map));
+       printf("sizeof dep_tab_t %d sizeof dep_tab %d\n", sizeof(dep_tab_t), sizeof(dep_tab));
+       printf("size of memory_trace_ent_t %d sizeof memory_trace %d\n", sizeof(memory_trace_ent_t), sizeof(memory_trace));
+       printf("size of CREATE3args %d\n", sizeof( CREATE3args));
+       printf("size of MKDIR3args %d\n", sizeof( MKDIR3args));
+       printf("size of READ3args %d\n", sizeof( READ3args));
+       printf("size of WRITE3args %d\n", sizeof( WRITE3args));
+       printf("size of RENAME3args %d\n", sizeof( RENAME3args));
+       printf("size of GETATTR3args %d\n", sizeof( GETATTR3args));
+       printf("size of SETATTR3args %d\n", sizeof( SETATTR3args));
+       printf("size of LINK3args %d\n", sizeof( LINK3args));
+       printf("size of SYMLINK3args %d\n", sizeof( SYMLINK3args));
+       printf("size of MKNOD3args %d\n", sizeof( MKNOD3args));
+       printf("size of RMDIR3args %d\n", sizeof( RMDIR3args));
+       printf("size of REMOVE3args %d\n", sizeof( REMOVE3args));
+       printf("size of LOOKUP3args %d\n", sizeof( LOOKUP3args));
+       printf("size of READDIR3args %d\n", sizeof( READDIR3args));
+       printf("size of READDIRPLUS3args %d\n", sizeof( READDIRPLUS3args));
+       printf("size of FSSTAT3args %d\n", sizeof( FSSTAT3args));
+       printf("size of FSINFO3args %d\n", sizeof( FSINFO3args));
+       printf("size of COMMIT3args %d\n", sizeof( COMMIT3args));
+       printf("size of ACCESS3args %d\n", sizeof( ACCESS3args));
+       printf("size of READLINK3args %d\n", sizeof( READLINK3args));
+
+
+}
+
+int io_thread ()
+{
+/* number of seconds the I/O thread pauses after each time trying to read the requests */
+#define IO_THREAD_PAUSE_TIME 1
+
+       int i;
+       int j = 0;
+
+       disk_io_status = read_trace ();
+       while (disk_io_status == TRACE_BUF_FULL) {
+
+               usleep (10000);
+        if ((j++%200)==0) {
+                printf("&&&&&&&&&& io thread, sleep %d seconds\n", j/10);
+        }
+
+               disk_io_status = read_trace ();
+               //printf ("io_thread, after read_trace, disk_index %d\n", disk_index);
+
+#ifdef SEQUEN_READ
+               for (i=0; i<SEQUEN_READ_NUM; i++) {
+                       add_to_dep_tab(CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size));
+               }
+#endif
+               //printf ("***************** IO THREAD SLEEP 1 s\n");
+               //print_cyclic_buffers();
+               //pthread_yield();
+       }
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+}
+
+int execute_thread()
+{
+       int i;
+       struct timeval playstart_time, playend_time;
+
+       sleep (10);             /* first let io_thread to run for a while */
+       init_time_offset();
+       printf ("trace_play\n");
+
+       gettimeofday(&playstart_time, NULL);
+
+       trace_play ();
+
+       gettimeofday(&playend_time, NULL);
+
+       {
+               int usec, sec;
+               sec = playend_time.tv_sec - playstart_time.tv_sec;
+               usec = sec * 1000000 + (playend_time.tv_usec - playstart_time.tv_usec);
+               sec = usec / 1000000;
+               usec = usec % 1000000;
+               printf("Total play time: %d sec %d usec\n", sec, usec);
+       }
+
+       print_result();
+}
+
+int init_thread ()
+{
+       pthread_attr_t  attr;
+       int arg;
+       int ret = 0;
+       pthread_t io_thread_var;
+       pthread_t execute_thread_var;
+
+       ret = pthread_attr_init (&attr);
+       if (ret!=0) {
+               perror("pthread_attr_init attr");
+               return ret;
+       }
+       ret = pthread_create (&(io_thread_var), &attr, &io_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+
+/*
+       ret = pthread_create (&(execute_thread_var), &attr, &execute_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+*/
+}
+
+void init_buffers()
+{
+       CYCLIC_INIT("memory_trace_index",memory_trace_index,MAX_MEMORY_TRACE_LINES);
+       CYCLIC_INIT("dep_tab_index     ",dep_tab_index,DEP_TAB_SIZE);
+       CYCLIC_INIT("dep_window_index  ",dep_window_index,DEP_TAB_SIZE);
+}
+
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       int i;
+       struct timeval in={1000000, 100};
+       
+       init_profile_variables();
+       if ((argc==1) || (argc==2 && !strcmp(argv[1],"-help"))) {
+               print_usage(0, argc, argv);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_write")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_write(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_trace")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_trace(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_aging")) {
+               if (argc!=3) {
+                       print_usage(3, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               check_aging (trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_statistics")) {
+               if (argc!=3) {
+                       print_usage(1, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               memset(fh_htable, 0, sizeof (fh_htable));
+               check_statistics (trace_file);
+               exit(0);
+       }
+
+       if (argc!=6) {
+               print_usage(2, argc, argv);
+               exit(0);
+       }
+       PLAY_SCALE = atoi (argv[4]);
+       RFS_ASSERT (PLAY_SCALE >=1 && PLAY_SCALE <=10000);
+
+       WARMUP_TIME = atoi (argv[5]);
+       RFS_ASSERT (WARMUP_TIME >=0 && WARMUP_TIME <=1000);
+       
+       print_memory_usage();
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_file_system ();
+       init_signal();
+       init_play (argv[1]);
+       //init_play ("capella:/p5/RFSFS");
+       init_fh_map();
+       read_fh_map (argv[3]);
+       //read_fh_map ("fh-path-map-play");
+       strcpy(trace_file, argv[2]);
+
+/* If ordered by TIMESTAMP,
+ * memory_trace_index.tail <= dep_tab_index.tail < dep_window_max <=
+ * dep_tab_index.head <= memory_trace_index.head
+ */
+
+       init_buffers();
+       //init_thread();
+       pthread_yield();
+       execute_thread();
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+}
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+
+#define READ_LINE_BUF_SIZE (MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR+2)
+#define SAFE_BYTES 1000
+#define READ_LINE_LENGTH (MAX_TRACE_LINE_LENGTH+SAFE_BYTES)
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                               RFS_ASSERT (0);
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+/*
+       if (!(strlen(line_buf[i])>80)) {
+               printf ("start %d start_disk_index %d disk_index %d strlen %d line_buf[%d] %s\n", start, start_disk_index, disk_index, strlen(line_buf[i]), i, line_buf[i]);
+               RFS_ASSERT (strlen(line_buf[i])>80);
+       }
+       if (!((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH)))
+               printf ("disk_index %d strlen %d line_buf[%d] %s\n", disk_index, strlen(line_buf[i]), i, line_buf[i]);
+       RFS_ASSERT ((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH));
+*/
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+#define OPS_FLAG_INC 0
+#define OPS_FLAG_PRINT 1
+int read_write_fh_statistics (int flag, char * buf, int timestamp)
+{
+       static FILE * fp = NULL;
+       char * p;
+       char c;
+       if (!fp) {
+               fp = fopen ("read_write_fh.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (buf, "fh");
+               RFS_ASSERT (p);
+               c = p[40+3];
+               p[40+3]=0;
+               fprintf(fp, "%s\n", p+3+24);
+               p[40+3]=c;
+       };
+       if (flag == OPS_FLAG_PRINT) { 
+               int disk_index = (int) buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+int write_statistics(int flag, char * buf, char * reply_buf, int trace_status)
+{
+       static FILE * fp = NULL;
+       int pre_size, size, count;
+       char * p = reply_buf;
+       if (!fp) {
+               fp = fopen ("write.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (p, "pre-size");
+               RFS_ASSERT (p);
+               sscanf (p, "pre-size %x", &pre_size); 
+               p += strlen("pre-size");
+               p = strstr (p, "size");
+               RFS_ASSERT (p);
+               sscanf (p, "size %x", &size); 
+               p = strstr (p, "count");
+               if (!p) 
+                       fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+               RFS_ASSERT (p);
+               sscanf (p, "count %x", &count); 
+               fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+       }
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = (int) buf;
+               int timestamp = (int) reply_buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+void ops_statistics (int ops_flag, int proc, int timestamp)
+{
+       static FILE * fp = NULL;
+       static struct {
+               int count;
+               int count_K;
+               int update_flag;
+               char name[32];
+       } ops[NOPS]={{0, 0, 0, "NULL"},{0, 0, 0, "GETATTR"},{0, 0, 1, "SETATTR"},{0, 0, 0, "ROOT"},
+                                 {0, 0, 0, "LOOKUP"},{0, 0, 0, "READLINK"},{0, 0, 0, "READ"},{0, 0, 1, "WRCACHE"},
+                                 {0, 0, 1, "WRITE"}, {0, 0, 1, "CREATE"},{0, 0, 1, "REMOVE"},{0, 0, 1, "RENAME"},
+                                 {0, 0, 1, "LINK"}, {0, 0, 1, "SYMLINK"},{0, 0, 1, "MKDIR"},{0, 0, 1, "RMDIR"},
+                                 {0, 0, 0, "READDIR"},{0, 0, 0, "FSSTAT"},{0, 0, 0, "ACCESS"},{0, 0, 0, "COMMIT"},
+                                 {0, 0, 0, "FSINFO"},{0, 0, 1, "MKNOD"}, {0, 0, 0, "PATHCONF"}, {0, 0, 0, "READDIRPLUS"}};
+
+       if (ops_flag == OPS_FLAG_INC) {
+               RFS_ASSERT (proc>=0 && proc<NOPS);
+               ops[proc].count ++;
+               if (ops[proc].count == 1000) {
+                       ops[proc].count_K ++;
+                       ops[proc].count = 0;
+               }
+       }
+       if (ops_flag == OPS_FLAG_PRINT) {
+               int i;
+               int update_K=0, update=0, total_K=0, total=0;
+               float f1, f2;
+               int disk_index = proc;
+
+               if (!fp) {
+                       fp = fopen ("mix.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               for (i=0; i<NOPS; i++) {
+                       total_K += ops[i].count_K;
+                       total += ops[i].count;
+                       if (ops[i].update_flag) {
+                               update_K += ops[i].count_K;
+                               update += ops[i].count;
+                       }
+               }
+               update_K += update/1000;
+               update = update%1000;
+               total_K += total/1000;
+               total = total%1000;
+
+               f1 = total_K;
+               f1 = f1*1000+total;
+               for (i=0; i<NOPS; i++) {
+                       f2 = ops[i].count_K;
+                       f2 = f2*1000+ops[i].count;
+                       fprintf (fp, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);  
+                       fprintf (stderr, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);      
+               }
+               f2 = update_K;
+               f2 = f2*1000+update;
+               fprintf (fp, "       total %8d,%03d\n", total_K, total);
+               fprintf (stderr, "       total %8d,%03d\n", total_K, total);
+               fprintf (fp, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);   
+               fprintf (stderr, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);       
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+               fprintf(stderr, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+
+void truncate_statistics (int flag, int proc, char * buf, char * reply_buf) 
+{
+#define TRACE_FH_SIZE2 16
+#define BLOCK_SIZE 4096
+       static int no_size_num = 0;
+       static int have_size_num = 0;
+       static int equal_size_num = 0;
+       static int first_size_num = 0;
+       static int truncate_num = 0;
+       static int truncate_size = 0;
+       static int truncate_KB = 0;
+       static int truncate_block_num = 0;
+       static int padding_num = 0;
+       static int padding_KB = 0;
+       static int padding_size = 0;
+       static FILE * fp = NULL;
+       char * p;
+       char * trace_fh;
+       int pre_size, size, count;
+       struct generic_entry * ent;
+
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = proc;
+               int timestamp = (int)buf;
+               if (!fp) {
+                       fp = fopen ("truncate.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               truncate_KB += truncate_size/1000;
+               truncate_size %= 1000;
+               padding_KB += padding_size/1000;
+               padding_size %= 1000;
+               fprintf(fp, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               fprintf(stderr, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               return;
+       }
+
+       p = strstr (&buf[TRACE_MSGID_POS], "fh");
+       RFS_ASSERT (p);
+       p+=3; 
+       trace_fh = p;
+               
+       if (proc==SETATTR) {
+               p = strstr (buf, " size ");
+       } else {
+               RFS_ASSERT (proc==WRITE);
+               p = strstr (reply_buf, " ftype 1 ");
+               RFS_ASSERT (p);
+               p = strstr (p, " size ");
+               RFS_ASSERT (p);
+               if (strstr(p, " ftype 1 ")) {
+                       fprintf (fp, "#### %s%s\n", buf, reply_buf);
+                       fprintf (stderr, "#### %s%s\n", buf, reply_buf);
+               }
+               RFS_ASSERT (!strstr(p, " ftype 1 "));
+       }
+       if (!p) {
+               no_size_num ++;
+               return;
+       }
+       have_size_num ++;
+
+       sscanf (p, " size %x", &size); 
+       if (size <0 || size > 2000000000) {
+               fprintf (fp, "#### size too big %x %s %s\n", size, buf, reply_buf);
+               fprintf (stderr, "#### size too big %x %s %s\n", size, buf, reply_buf);
+       }
+                                                       
+       RFS_ASSERT (size >=0 && size <2000000000);              
+       ent = generic_lookup (trace_fh+24, TRACE_FH_SIZE2, 0, fh_htable, FH_HTABLE_SIZE);
+       if (ent) {
+               if (ent->key3 != size) {
+                       if (proc==SETATTR) {
+                               //printf ("%s\n", buf);
+                               //printf ("size change fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                               if (ent->key3 > size) {
+                                       truncate_num ++;
+                                       truncate_size += ent->key3 - size;
+                                       truncate_block_num += (ent->key3+BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       if (size!=0) {
+                                               //fprintf (stderr, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               //fprintf (fp, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               truncate_block_num -= (size + BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       }
+                                       if (truncate_size > 1000000000) {
+                                               truncate_KB += truncate_size/1000;
+                                               truncate_size %= 1000;
+                                       }
+                               } else {
+                                       padding_num ++; 
+                                       //printf ("%s\n", buf);
+                                       //printf ("padding fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                                       padding_size += size - ent->key3;
+                                       if (padding_size > 1000000000) {
+                                               padding_KB += padding_size/1000;
+                                               padding_size %= 1000;
+                                       }
+                               }
+                       }
+                       ent->key3 = size; 
+               }else 
+                       equal_size_num++;
+       } else {
+               generic_insert(trace_fh+24, TRACE_FH_SIZE2, size, fh_htable, FH_HTABLE_SIZE);
+               first_size_num ++;
+       }
+};
+
+int get_timestamp (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       str[10]=0;
+       ret = atoi(str);
+       RFS_ASSERT (ret >1000000000 && ret <2000000000);
+       return ret;
+}
+
+int check_aging (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               switch (proc) {
+               int off, count, size;
+               char * t;
+               case CREATE: printf("%s\n", "create"); break;
+               case MKDIR: printf("%s\n", "mkdir"); break;
+               case REMOVE: printf("%s\n", "remove"); break;
+               case RMDIR: printf("%s\n", "rmdir"); break;
+               case WRITE: 
+                       t = buf;
+                       t = strstr (t, "off");
+               RFS_ASSERT (t);
+                   t+=4;
+                       sscanf (t, "%x", &off);
+                       RFS_ASSERT (off>=0 && off<0x7FFFFFFF)
+                       t = strstr (t, "count");
+                   RFS_ASSERT (t);
+                       t+=6;
+                       sscanf (t, "%x", &count);
+                       RFS_ASSERT (count <= 32768);
+                       printf("%s off %x count %x\n", "write", off, count); 
+                       //printf("%s count %x\n", "write", count); 
+                       break;
+               case SETATTR: 
+                       t = strstr (buf, " size ");
+                       if (t) {
+                               sscanf (t, " size %x", &size);
+                               printf ("%s size %x\n", "setattr", size);
+                       }
+               }
+               if ((disk_index%10000)==0) {
+                       fprintf(stderr, "%d disk trace passed\n", disk_index);
+               }
+       };
+
+       fprintf(stderr, "%d disk trace parsed\n", disk_index);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, -1);
+}
+
+
+int check_statistics (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+       static int last_timestamp_sec = -1;
+       int timestamp_sec;
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               timestamp_sec = get_timestamp(buf);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               if (proc!= WRITE && proc!=SETATTR && proc!=READ) {
+                       continue;
+               }
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               if (proc==READ || proc==WRITE) 
+                                                       read_write_fh_statistics (OPS_FLAG_INC, buf, 0);
+                                               if (proc == WRITE)
+                                                       write_statistics (OPS_FLAG_INC, buf, reply_buf, trace_status);
+                                               if (proc==WRITE || proc==SETATTR) 
+                                                       truncate_statistics (OPS_FLAG_INC, proc, buf, reply_buf);
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       //printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if *
+               if ((missing_reply_num > memory_trace_size/10) && (missing_reply_num > 100)) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               if (last_timestamp_sec == -1) {
+                       last_timestamp_sec = timestamp_sec;
+               } else if (timestamp_sec - last_timestamp_sec >=3600) {
+                       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+                       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+                       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+                       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+                       last_timestamp_sec = timestamp_sec;
+               }
+/*
+               if ((memory_trace_size%10000)==0) {
+                       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+                       ops_statistics (OPS_FLAG_PRINT, -1);
+                       truncate_statistics (OPS_FLAG_PRINT, -1, NULL, NULL);
+               }
+*/
+       };
+
+       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+}
+
+
+/* This routine output all the requests, together with their replies */
+int pair_trace (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+       FILE * outputfp;
+
+       outputfp = fopen ("pair.output", "w");
+       RFS_ASSERT (outputfp);
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+               fprintf (outputfp, "%s\n", buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       fprintf(outputfp, "%s", reply_buf);
+                                       trace_status = find_reply_status(reply_buf);
+                                       if (debug)
+                                               fprintf(stderr, "reply found trace_status %d\n", find_reply_status(reply_buf));
+                               };
+               }
+               }
+
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       fprintf (stderr, "%s no reply\n", buf);
+                       fprintf(outputfp, "missing_reply\n");
+                       missing_reply_num ++;
+               }
+
+               if (missing_reply_num > memory_trace_size/10 && missing_reply_num >100) {
+                       fprintf (stderr, "missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+
+               memory_trace_size ++;
+
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+/* This routine output all the write requests, together with their replies. It is used for
+ * analysis of write requests: appended bytes, overwrite bytes etc
+ */
+int pair_write (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int pair_write_debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               if (!strstr(buf, "write")) 
+                       continue;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (pair_write_debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               /* store the request to memory */
+               //strcpy (memory_trace[memory_trace_size].line, buf);
+               //memory_trace[memory_trace_size].disk_index = disk_index;
+
+               /* find and store the reply status and reply fhandle to memory */
+               //memory_trace[memory_trace_size].trace_status = NFS3ERR_RFS_MISS;
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (pair_write_debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       int pre_size, size, count;
+                               //memory_trace[memory_trace_size].trace_status = find_reply_status(reply_buf);
+                                       if (pair_write_debug)
+                                               printf("reply found trace_status %d\n", find_reply_status(reply_buf));
+                                               //break;
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               p = strstr (p, "pre-size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "pre-size %x", &pre_size); 
+                                               p += strlen("pre-size");
+                                               p = strstr (p, "size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "size %x", &size); 
+                                               p = strstr (p, "count");
+                                               if (!p) 
+                                                       printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "count %x", &count); 
+                                               printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               break;
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if (missing_reply_num > memory_trace_size/10) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               /*
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               */
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+
+int read_trace ()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+       memory_trace_ent_t * ent=NULL;
+
+       start_profile (&read_trace_profile);
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+       
+#ifdef notdef
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               if (disk_index==1) {
+                       trace_timestamp1 = get_timestamp (buf);
+               } else
+                       trace_timestamp2 = get_timestamp (buf);
+#endif
+               /* store the request to memory */
+               ent = &(memory_trace[memory_trace_index.head]);
+               strcpy (ent->line, buf);
+               ent->disk_index = disk_index;
+
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               };
+
+               if (ent->trace_status == NFS3ERR_RFS_MISS)
+                       missing_reply_num ++;
+
+               if (MAX_COMMAND_REPLY_DISTANCE > 1) {
+                       if ((missing_reply_num > disk_index/5) && (missing_reply_num > 100)) {
+                               printf ("missing_reply_num %d too high for disk_index %d\n", missing_reply_num, disk_index);
+                               exit (0);
+                       }
+               }
+
+               /* find and store the reply trace fhandle for create-class requests */
+               if (ent->trace_status==NFS3_OK) {
+                       if (strstr(buf, "create") || strstr(buf, "mkdir") 
+                               || (strstr(buf, "symlink") && (buf[TRACE_VERSION_POS]!='2')) 
+                               || strstr(buf, "mknod") ) {
+                               p = find_reply_trace_fh(reply_buf);
+                               memcpy(ent->reply_trace_fh, p, TRACE_FH_SIZE);
+                       } else
+                               memset(ent->reply_trace_fh, 0, TRACE_FH_SIZE);
+               }
+
+               add_to_dep_tab(memory_trace_index.head);
+
+               if (((disk_index+1)%20000)==0) {
+                       fprintf(stderr, "%d disk trace parsed \n", disk_index+1);
+               };
+       };
+
+       end_profile (&read_trace_profile);
+       return TRACE_BUF_FULL;
+}
+#else  /* not defined REDUCE_MEMORY_TRACE_SIZE */
+int read_trace ()
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(trace_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, MAX_TRACE_LINE_LENGTH, fp)) {
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+               /* store the request to memory */
+               strcpy (memory_trace[memory_trace_size].line, buf);
+               memory_trace[memory_trace_size].disk_index = disk_index;
+               memory_trace_size ++;
+
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               if ((disk_index%100000)==0)
+                       fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+               disk_index ++;
+       }
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+}
+#endif
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+
+       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index));
+       RFS_ASSERT (memory_trace[memory_trace_index.tail].disk_index <= disk_index);
+       RFS_ASSERT (memory_trace[CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size)].disk_index >=disk_index);
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index = CYCLIC_ADD(memory_index,1,memory_trace_index.size);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index = CYCLIC_MINUS(memory_index,1,memory_trace_index.size);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       p = line+TRACE_MSGID_POS+2;     /* at least one letter for msgid and one letter for space */
+       if (strstr(p, "OK"))
+               return NFS3_OK;
+       if (strstr(p, "lookup 2"))
+               return 0x2;
+       if (strstr(p, "create d"))
+               return 0xd;
+       if (strstr(p, "setattr 1"))
+               return 0x1;
+       if (strstr(p, "setattr 2712")) /* 10002 NFS3ERR_NOT_SYNC */
+               return 0x2712;
+       if (strstr(p, "lookup d"))
+               return 0xd;
+       if (strstr(p, "read d"))
+               return 0xd;
+       if (strstr(p, "write d"))
+               return 0xd;
+       if (strstr(p, "write 46"))
+               return 0x46;
+       if (strstr(p, "getattr 46"))
+               return 0x46;
+       if (strstr(p, "mkdir d"))
+               return 0xd;
+       printf ("line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       printf ("!!!!!!!!!!!!!!!!!!!!!!!!\n");
+       fprintf (stderr, "line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       fprintf (stderr, "!!!!!!!!!!!!!!!!!!!!!!!!\n");
+}
+
+inline int find_reply_status_old (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p)
+               printf ("find_reply_trace_fh line %s\n", line);
+       RFS_ASSERT (p);
+       return p+6;
+}
+
+#ifndef NO_DEPENDENCY_TABLE
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+#endif
+
+inline int is_play_candidate (int dep_index)
+{
+       int proc = dep_tab[dep_index].proc;
+       int status = dep_tab[dep_index].status;
+       int trace_status = dep_tab[dep_index].trace_status;
+
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       /* for a failed create in trace, trace_replay just ignore many time the trace create fail
+        * due to access control, but trace_play will success because our access control
+        * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+        */
+       if ((proc==CREATE || proc==MKDIR) && (trace_status!=NFS3_OK) && (status!=NFS3ERR_RFS_MISS)) {
+               if (dependency_debug)
+                       printf ("disk[%d] ignore failed create/mkdir in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               failed_create_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_OTHER_FAILED_COMMAND
+       if (((trace_status == NFS3ERR_ACCES) && (proc==READ || proc==WRITE || proc==LOOKUP)) || 
+           ((trace_status == NFS3ERR_PERM) && (proc==SETATTR))                                                                         ){
+               if (dependency_debug)
+                       printf ("disk[%d] ignore other failed command in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               
+               failed_other_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK) ) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+/* This is actually take care in get_nextop by checking fh_map error when dep_index==min_dep_index */
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+/*
+       if ((    ((dep_tab[dep_index].disk_index==262213) || (dep_tab[dep_index].disk_index==214402))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1100.txt")) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+*/
+       if ((    ((dep_tab[dep_index].disk_index==423727) || (0))
+                 && !(strncmp(trace_file, "anon-lair62-011130-1500.txt", strlen("anon-lair62-011130-1500.txt"))) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+       /* this line is about the mkdir 116d9d originally in anon-lair62-011130-1400.txt */
+       if (!strncmp(dep_tab[dep_index].line, "1007147245.194201", strlen("1007147245.194201"))) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_FSSTAT_COMMAND
+       /* the file handle used in this command is not processed properly by pre-processing */
+       if (proc==FSSTAT) {
+               char * trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+               fh_map_t * fh = lookup_fh (trace_fh);
+               if (!fh) {
+                       skipped_fsstat_command_num++;
+                       return FALSE;
+               }
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+static inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+#define INIT_MIN_WAIT_VALUE -999
+       static int min_wait_fhandle_dep_index = INIT_MIN_WAIT_VALUE;
+       int proc;
+       int flag;
+
+       if (min_wait_fhandle_dep_index == -999)
+               min_wait_fhandle_dep_index = dep_window_index.head;
+
+       for (i=0; i<CYCLIC_NUM(dep_window_index); i++) {
+               dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (CYCLIC_LESS(dep_tab_index,dep_index,min_wait_fhandle_dep_index)) 
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       if (dep_index==dep_window_index.tail) {
+                                               if (!profile_debug) 
+                                                       printf ("fh_path_map error disk[%d] state DEP_FLAG_WAIT_FHANDLE to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                                               fh_path_map_err_num ++;
+                                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                                               continue;
+                                       }
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#define DEPENDENCY_TIMEOUT 5
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       if (tmp.sec >= DEPENDENCY_TIMEOUT) {
+                                               printf("dep_tab[%d].flag %d disk_index %d line %s\n", dep_index,
+                                                       dep_tab[dep_index].flag, dep_tab[dep_index].disk_index,
+                                                       dep_tab[dep_index].line);
+                                       }
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_window_index.head;
+                                       for (j=CYCLIC_ADD(dep_index,1,dep_window_index.size); CYCLIC_LESS(dep_window_index,j,dep_window_index.head); j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else /*NO_DEPENDENCY_TABLE undefined */
+       /* this part of code will be invalid after CYCLIC buffer design */
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { 
+                                               /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+
+       sfs_gettime (&current); 
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current.sec>timeout.sec) ||
+                               ((current.sec==timeout.sec) && (current.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+                               finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT);
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                               }
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               //printf ("timeout request: biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+               num_out_reqs++;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if (biod_reqp[biod_index].xid == xid) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[39], "%x %x", &msgid, &nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       dep_tab[dep_index].reply_line = find_reply_line (line, dep_tab[dep_index].disk_index);
+       if (dep_tab[dep_index].reply_line == NULL) {
+               //printf ("disk[%d] can not find the reply line, assume trace_status OK\n", dep_tab[dep_index].disk_index);
+               dep_tab[dep_index].trace_status = NFS3ERR_RFS_MISS;
+               missing_reply_num ++;
+       } else 
+               dep_tab[dep_index].trace_status = find_reply_status (dep_tab[dep_index].reply_line);
+#endif
+}
+
+void adjust_play_window (int flag, int * poll_timeout)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int i;
+       char * line;
+       cyclic_index_t old_dep_window_index = dep_window_index;
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, begin\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("                adjust_play_window, begin\n");
+#endif
+
+       while ((!CYCLIC_EMPTY(dep_window_index)) && (dep_tab[dep_window_index.tail].flag == DEP_FLAG_DONE)) {
+#ifdef notdef
+               //CYCLIC_PRINT (memory_trace_index);
+               //printf("MOVE_TAIL_TO memory_index %d\n", dep_tab[dep_tab_index.tail].memory_index);
+               RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+               RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+               printf("%d is done\n", dep_window_index.tail);
+#endif
+               CYCLIC_MOVE_TAIL(dep_tab_index);
+               CYCLIC_MOVE_TAIL(dep_window_index);
+
+#ifdef notdef
+               CYCLIC_PRINT (dep_tab_index);
+               CYCLIC_PRINT (dep_window_index);
+
+               if (! (dep_tab_index.tail == dep_window_index.tail)) {
+                       CYCLIC_PRINT(dep_tab_index);
+                       CYCLIC_PRINT(dep_window_index);
+               };
+               RFS_ASSERT ( dep_tab_index.tail == dep_window_index.tail);
+#endif
+
+               if (!CYCLIC_EMPTY(dep_tab_index)) {
+#ifdef notdef
+                       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+                       if (!(CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head))) {
+                               CYCLIC_PRINT(memory_trace_index);
+                               CYCLIC_PRINT(dep_tab_index);
+                               printf("dep_tab[head-1].memory_index, %d [tail].memory_index %d\n", 
+                                       dep_tab[CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size)].memory_index,
+                                       dep_tab[dep_tab_index.tail].memory_index);
+                       }
+                       RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+#endif
+                       CYCLIC_SET_TAIL_TO(&memory_trace_index, dep_tab[dep_tab_index.tail].memory_index);
+                       //printf ("set memory_trace_index to %d=%d, dep_tab_index.tail %d\n", memory_trace_index.tail, dep_tab[dep_tab_index.tail].memory_index, dep_tab_index.tail);
+               } else {
+               //      CYCLIC_MOVE_TAIL (memory_trace_index);
+               }
+       }
+
+       while (CYCLIC_EMPTY(dep_tab_index)) {
+               
+               if (disk_io_status == TRACE_FILE_END) 
+                       return;
+               else {
+                       //printf ("************** ADJUST_PLAY_WINDOW sleep 1 s\n"); 
+                       //print_cyclic_buffers();
+                       pthread_yield();
+                       //usleep (1000);
+               }
+       }
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (CYCLIC_NUM(dep_window_index) == MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, dep_tab_size %d dep_window_max %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", dep_tab_size, dep_window_max, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       //RFS_ASSERT (dep_window_max < min_dep_index+MAX_PLAY_WINDOW);
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout = 0;
+       else if (CYCLIC_NUM(dep_window_index)==CYCLIC_NUM(dep_tab_index)) {
+               *poll_timeout = 1000000;        /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_index.head].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_index.head].timestamp.tv_usec;
+               if (adjust_play_window_debug>=2)
+                       printf ("dep_tab[dep_window_index.head %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_index.head, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+/*
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_max, dep_tab[dep_window_max].timestamp.tv_sec, dep_tab[dep_window_max].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+*/
+
+               //RFS_ASSERT ((tmp.sec < 1000));
+               if (tmp.sec > 1000)
+                       tmp.sec = 1000;
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout = 0;
+               } else
+                       *poll_timeout = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_max].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_max].timestamp.tv_usec;
+               tmp1.sec = dep_tab[dep_window_max-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[dep_window_max-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout %d \n", 
+               flag, old_dep_window_index.tail, dep_window_index.tail, old_dep_window_index.head,
+               dep_window_index.head, *poll_timeout);
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, end\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("        adjust_play_window, end\n\n");
+#endif
+       //CYCLIC_ASSERT(4);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+#if    0       /* commented out by G. Jason Peng */
+       RFS_ASSERT (read_data_owe_GB==0);
+       printf("read_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",read_data_total_GB, read_data_total, read_data_owe_GB, read_data_owe, (read_data_owe)/(read_data_total/100), read_data_adjust_times);
+       printf("write_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",write_data_total_GB, write_data_total, write_data_owe_GB, write_data_owe, (write_data_owe)/(write_data_total/100), write_data_adjust_times);
+       printf("poll_timeout_0_num %d poll_timeout_pos_num %d\n", poll_timeout_0_num, poll_timeout_pos_num);
+       printf("failed_create_command_num_in_original_trace %d\nfailed_other_command_num_in_original_trace %d\nskipped_readlink_command_num %d\nskipped_custom_command_num %d\nfh_path_map_err_num %d\nskipped_fsstat_command_num %d\nmissing_reply_num %d\nrename_rmdir_noent_reply_num %d\nrmdir_not_empty_reply_num %d\nloose_access_control_reply_num %d\nlookup_err_due_to_rename %d\nlookup_err_due_to_parallel_remove %d\nlookup_eaccess_enoent_mismatch %d\nread_io_err_num %d\nstale_fhandle_err_num %d abnormal_EEXIST_num %d abnormal_ENOENT_num %d proper_reply_num %d run_stage_proper_reply_num %d\n", 
+                       failed_create_command_num,
+                       failed_other_command_num,
+                       skipped_readlink_command_num, 
+                       skipped_custom_command_num,
+                       fh_path_map_err_num, 
+                       skipped_fsstat_command_num, 
+                       missing_reply_num, 
+                       rename_rmdir_noent_reply_num, 
+                       rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, 
+                       lookup_err_due_to_rename_num, 
+                       lookup_err_due_to_parallel_remove_num,
+                       lookup_eaccess_enoent_mismatch_num, 
+                       read_io_err_num, 
+                       stale_fhandle_err_num,
+                       abnormal_EEXIST_num,
+                       abnormal_ENOENT_num,
+                       proper_reply_num, run_stage_proper_reply_num);
+#endif
+
+    clnt_destroy(NFS_client);
+    biod_term();
+
+//  print_dump(Client_num, Child_num);
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               //RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               if (memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE)) {
+                       int i;
+                       printf ("fh_map[%d].trace_fh %s trace_fh %s", p->key3, fh_map[p->key3].trace_fh, trace_fh);
+                       for (i=0; i<fh_i; i++) {
+                               int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                               int * p = (int *)fh_map[i].trace_fh;
+                               printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                               printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, fh_map[i].trace_fh, fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+                       }
+#endif
+                       RFS_ASSERT (0);
+               }
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               /* It's possible that in fh-path-map, many trace_fh are corresponding to one path
+                * some of it may be the result of lookup after symlink, which is not handled
+                * properly as new created objects 
+                */
+#ifdef TAKE_CARE_SYMBOLIC_LINK
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+#endif
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       strncpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       //show_fhandle(play_fh);
+               } else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+inline fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i[%d] trace_fh %s path %s play_fh:\n", p->key3, fh_map[p->key3].trace_fh, fh_map[p->key3].path);
+                       //show_fhandle(&fh_map[p->key3].play_fh);
+               }
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+int lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+       return (reply.status);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+       int lineno = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               lineno ++;
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7) ||
+                       !strncmp (trace_path, "LN", 2)                  ) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       int ret = lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);               
+                       if (ret!=NFS3_OK) {
+                               printf ("lineno %d %s\n", lineno, buf);
+                       }
+                       RFS_ASSERT (ret == NFS3_OK);
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline free_biod_req (int biod_index)
+{
+       RFS_ASSERT (biod_reqp[biod_index].in_use == TRUE);
+       biod_reqp[biod_index].in_use = FALSE;
+       num_out_reqs --;
+}
+
+inline void finish_request (int biod_index, int dep_index, int status)
+{
+       /* the ending operation, same as when a request time out */
+
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       free_biod_req (biod_index);
+
+       dep_tab[dep_index].status = status;
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = -dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].flag = DEP_FLAG_DONE;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+int poll_timeout = 0;          /* timeout in usecs */
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+       static int last_print_time = -1;
+
+       if (num_out_reqs == max_biod_reqs) {
+               return -1;
+       }
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+
+       end_profile(&total_profile);
+       if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+               last_print_time = total_profile.in.tv_sec;
+               //fprintf (stderr, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+               fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+/*
+               CYCLIC_PRINT (dep_tab_index);
+               {
+                       int tmp = CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size);
+                       printf("dep_tab_index.head-1 %d disk_index %d tail %d disk_index %d\n", tmp, dep_tab[tmp].disk_index,
+                       dep_tab_index.tail, dep_tab[dep_tab_index.tail].disk_index);
+               }
+*/
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+/*
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+*/
+#endif
+               if ((total_profile.in.tv_sec > 100)) {
+                       can_not_catch_speed_num_total += can_not_catch_speed_num;
+               }
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+#ifdef notdef  /* place to set request timeout. G. Jason Peng */
+       call_timeout.sec = 2; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+#else
+       call_timeout.sec = 0;
+       call_timeout.usec = 500000;
+       //call_timeout.usec = 14000;
+       //call_timeout.usec = 13000;
+       //call_timeout.usec = 6000;
+       //call_timeout.usec = 8000;
+       //call_timeout.usec = 10000;
+#endif
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#else
+
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    RFS_ASSERT (reqp->xid != 0);
+    reqp->timeout = reqp->start;
+    ADDTIME (reqp->timeout, call_timeout);
+    dep_tab[dep_index].flag = DEP_FLAG_SENT;
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+}
+
+void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_status)
+{
+       if (((status!=trace_status)) && (status!=NFS3_OK) && (trace_status!=NFS3ERR_RFS_MISS)) {
+               if (!profile_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else // if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_status == 0)) {
+                               /* trace_status could be EAGAIN */
+                       if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) ) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+               } else if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status == NFS3ERR_NOENT)) {
+                       /* if there is a remove in front of the lookup, but it is
+                        * actually executed later than the lookup
+                        */
+                       lookup_err_due_to_parallel_remove_num ++;
+#endif
+#ifndef TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+               /* if the looked return EACCESS in the trace, means the object still exists
+                * should have initialized, right not don't initialize it, hence play status 
+                * could be ENOENT
+                */
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3ERR_ACCES)) {
+                       lookup_eaccess_enoent_mismatch_num ++;
+#endif
+#ifdef TOLERANT_READ_IO_ERR
+               } else if ((proc==READ) && (status==NFS3ERR_IO) && (trace_status==NFS3_OK)) {
+                       read_io_err_num ++;
+#endif
+#ifdef TOLERANT_STALE_FHANDLE_ERR
+               } else if ((status==NFS3ERR_STALE) && (trace_status==NFS3_OK)) {
+                       printf ("!!!!!!! STALE FILE HANDLE \n");
+                       //sleep(1);
+                       stale_fhandle_err_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=dep_window_index.tail; CYCLIC_LESS(dep_window_index,i,dep_window_index.head); i++) 
+                               printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       if (status==EEXIST) {
+                               abnormal_EEXIST_num ++;
+                       } else if (status == ENOENT) {
+                               abnormal_ENOENT_num ++;
+                       } else
+                               RFS_ASSERT (0);
+               }
+       } else {
+               proper_reply_num ++;
+               if (total_profile.in.tv_sec >= WARMUP_TIME) 
+                       run_stage_proper_reply_num ++;
+       }
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+inline int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_status;
+       char * errmsg;
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+
+       if (busy_flag == BUSY) {
+               poll_timeout = 0;
+               poll_timeout_0_num ++;
+       } else {
+               poll_timeout = 2000;    /* 10000 or 2000 is a better number in non-debugging state */
+               //poll_timeout = 0;     /* 10000 or 2000 is a better number in non-debugging state */
+               poll_timeout_pos_num ++;
+       }
+
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       if (biod_reqp[biod_index].in_use==1) {
+               RFS_ASSERT (dep_tab[dep_index].biod_req_index == biod_index);
+       } else {
+               printf ("biod_index %d reply received but the request has been time out\n", biod_index);
+               return -1;
+       }
+
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = dep_tab[dep_index].reply_line;
+       trace_status = dep_tab[dep_index].trace_status;
+
+       /* print the result, trace play progress indicator 
+       if (rfs_debug || (      !profile_debug && ((dep_index %10000)==0)       ) )
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+       */
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status);
+       
+       /* we set 100 seconds warm up time */
+       if ((total_profile.in.tv_sec >= WARMUP_TIME)) {
+       /* get statistics */
+       if (status == trace_status || (status==NFS3_OK && trace_status==NFS3ERR_RFS_MISS) ) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       }
+       
+       //start_profile (&add_create_object_profile);
+
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+               RFS_ASSERT (reply_line);
+#endif
+               if (status!=NFS3_OK) {
+                       /* commented out for 1022 */
+                       printf ("!!!!!! Should have been an ASSERTION FAILURE \n");
+                       RFS_ASSERT (proc==SYMLINK);
+                       RFS_ASSERT (0);
+               } else {
+                       if (proc!=SYMLINK || line[TRACE_VERSION_POS]!='2')
+                               add_new_file_system_object(proc, dep_index, line, reply_line);
+               }
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+       reply_trace_fh = dep_tab[dep_index].reply_trace_fh;
+#else
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+#endif
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+#endif
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       /* just to preserve the original reply line not changed */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+#endif
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, dep_window_max> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+
+       disk_io_status = read_trace();
+       RFS_ASSERT (!CYCLIC_EMPTY(dep_tab_index));
+       CYCLIC_MOVE_HEAD(dep_window_index);
+
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while (!CYCLIC_EMPTY(dep_tab_index)) {
+               if ((total_profile.in.tv_sec > 600)) {
+                       printf ("the process has run for more than 600 seconds, exit\n");
+                       goto END;
+               }
+
+               if (busy_flag == IDLE) {
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+                       if (disk_io_status!=TRACE_FILE_END) {
+                               disk_io_status = read_trace();
+                       };
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1) {
+                       busy_flag = BUSY;
+               }
+               end_profile (&execute_next_request_profile);
+
+
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+#endif
+               end_profile (&receive_next_reply_profile);
+
+               CYCLIC_ASSERT (0);
+       }
+       end_profile (&total_profile);
+
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       if (num_out_reqs !=0 ) {
+               printf ("num_out_reqs %d\n", num_out_reqs);
+               CYCLIC_PRINT(dep_tab_index);
+       }
+       RFS_ASSERT(num_out_reqs==0);
+
+END:
+       printf ("trace starttime %d, trace_end_time %d trace_duration %d\n", trace_timestamp1, trace_timestamp2,
+               trace_timestamp2 - trace_timestamp1);
+       printf ("can_not_catch_speed_num_total %d can_not_catch_speed_num_last_10_seconds %d", 
+               can_not_catch_speed_num_total, can_not_catch_speed_num);
+       printf ("total_profile.about: %s\n", total_profile.about);
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       //print_profile ("check_timeout", &check_timeout_profile);
+       //printf("\n");
+       //print_profile ("adjust_play_window", &adjust_play_window_profile);
+       //printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument_profile", &prepare_argument_profile);
+       print_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply_profile", &decode_reply_profile);
+       print_profile ("check_reply_profile", &check_reply_profile);
+       print_profile ("fgets_profile", &fgets_profile);
+       print_profile ("read_line_profile", &read_line_profile);
+       print_profile ("read_trace_profile", &read_trace_profile);
+       //print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("dep_tab_index.tail %d dep_tab_index.head %d num_out_reqs %d\n", dep_tab_index.tail, dep_tab_index.head, num_out_reqs);
+}
+
+int CYCLIC_SET_TAIL_TO(cyclic_index_t * index, int dest) 
+{ 
+       cyclic_index_t indextmp, indextmp2;
+       int oldnum, num;
+       indextmp = *index;
+       indextmp2 = indextmp;
+       oldnum = CYCLIC_NUM(indextmp); 
+
+       if (! ((dest>=0) && (dest<indextmp.size))) {
+               CYCLIC_PRINT(indextmp);
+               printf("dest %d\n", dest);
+       }
+       RFS_ASSERT ((dest>=0) && (dest<indextmp.size));
+       index->tail = dest; 
+       indextmp2.tail = dest;
+       num = CYCLIC_NUM(indextmp2); 
+
+       if (num > oldnum) { 
+               CYCLIC_PRINT(indextmp);
+               CYCLIC_PRINT(indextmp2);
+               printf("dest %d old_num %d num %d\n", dest, oldnum, num);
+       }
+       RFS_ASSERT (num <= oldnum);
+}
+
+int flush_junk()
+{
+       int i;
+       for (i=0; i<500; i++) {
+               printf ("*************************************************************\n");
+       }
+       fflush(stdout);
+}
+
+int CYCLIC_ASSERT (int i)
+{
+       int j;
+       if (!(dep_tab_index.tail == dep_window_index.tail)) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       if (!((dep_window_index.head == dep_tab_index.head) || 
+                  CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ) )) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       for (i=0, j=0; i<max_biod_reqs; i++) {
+               if (biod_reqp[i].in_use == 1)
+                       j++;
+       }
+       RFS_ASSERT (num_out_reqs==j);
+/*
+               RFS_ASSERT ((dep_window_index.head == dep_tab_index.head) || 
+                          CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ));
+*/
+}
+
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_chd.3thread.c b/TBBT/trace_play/sfs_c_chd.3thread.c
new file mode 100644 (file)
index 0000000..195beb0
--- /dev/null
@@ -0,0 +1,3815 @@
+/* Try to change thread scheduling and uses three threads */
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static int read_trace(void);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+void adjust_play_window (int flag, int * poll_timeout_arg);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern inline fh_map_t * lookup_fh (char * trace_fh );
+static void finish_request (int biod_index, int dep_index, int status, int dep_flag);
+static inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+static inline char * find_lead_trace_fh(int proc, char * line);
+static inline char * find_reply_trace_fh (char * line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/* as long as the inital value is different, then it's OK */
+int recv_num = 0;
+int timeout_num = 0;
+int send_num = 0;
+int exit_flag = 0;
+int async_rpc_sem;
+int no_progress_flag = 0;
+int num_out_reqs_statistics[MAX_OUTSTANDING_REQ+1];
+int num_out_reqs_statistics_at_timeout[MAX_OUTSTANDING_REQ+1];
+
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                       22, 19};
+void print_usage(int pos, int argc, char ** argv)
+{
+       int i;
+       printf("sfs3 hostname:mount_dir trace_file|stdin fh_map_file play_scale warmup_time(in seconds) \n");
+       printf("sfs3 -pair_trace trace_file\n");
+       printf("sfs3 -pair_write trace_file\n");
+       printf("sfs3 -help\n");
+       printf ("pos %d argc %d", pos, argc);
+       for (i=0; i<argc; i++) {
+               printf(" %s", argv[i]);
+       } 
+       printf ("\n");
+       exit;
+}
+
+void print_cyclic_buffers ()
+{
+       CYCLIC_PRINT(memory_trace_index);
+       CYCLIC_PRINT(dep_tab_index);
+       CYCLIC_PRINT(dep_window_index);
+}
+
+void add_to_dep_tab(int i)
+{
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       dep_tab_t * ent;
+
+    trace_fh = strstr (memory_trace[i].line, "fh");
+    if (!trace_fh)
+       printf ("memory_trace[%d].line %s\n", i, memory_trace[i].line);
+    RFS_ASSERT (trace_fh);
+    trace_fh += 3;
+    fh_map_entry = lookup_fh (trace_fh);
+    if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+        req_num_with_discard_fh ++;
+               return;
+       }
+    if (fh_map_entry)
+        req_num_with_init_fh ++;
+    else
+        req_num_with_new_fh ++;
+                                                                                                                              
+       RFS_ASSERT (!CYCLIC_FULL(dep_tab_index));
+       ent = &(dep_tab[dep_tab_index.head]);
+
+    ent->disk_index = memory_trace[i].disk_index;
+       ent->memory_index = i;
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+    ent->trace_status = memory_trace[i].trace_status;
+    ent->reply_trace_fh = memory_trace[i].reply_trace_fh;
+#endif
+    ent->line = memory_trace[i].line;
+    init_dep_tab_entry(dep_tab_index.head);
+
+    if (rfs_debug && (i%100000)==0)
+       printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_index.head, ent->disk_index, i, memory_trace[i].disk_index);
+    CYCLIC_MOVE_HEAD(memory_trace_index);
+    CYCLIC_MOVE_HEAD(dep_tab_index);
+}
+
+void init_profile_variables ()
+{
+       init_profile ("total_profile", &total_profile);
+       init_profile ("execute_next_request_profile", &execute_next_request_profile);
+       init_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       init_profile ("invalid_get_nextop_profile",&invalid_get_nextop_profile);
+       init_profile ("prepare_argument_profile", &prepare_argument_profile);
+       init_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       init_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       init_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       init_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       init_profile ("decode_reply_profile", &decode_reply_profile);
+       init_profile ("check_reply_profile", &check_reply_profile);
+       init_profile ("add_create_object_profile", &add_create_object_profile);
+       init_profile ("check_timeout_profile", &check_timeout_profile);
+       init_profile ("adjust_play_window_profile",&adjust_play_window_profile);
+       init_profile ("fgets_profile",&fgets_profile);
+       init_profile ("read_line_profile",&read_line_profile);
+       init_profile ("read_trace_profile",&read_trace_profile);
+}
+
+static char trace_file[256]="anon-lair62-011130-1200.txt";
+int print_memory_usage()
+{
+       printf("size of fh_map_t %d size of fh_map %d\n", sizeof(fh_map_t), sizeof(fh_map));
+       printf("sizeof dep_tab_t %d sizeof dep_tab %d\n", sizeof(dep_tab_t), sizeof(dep_tab));
+       printf("size of memory_trace_ent_t %d sizeof memory_trace %d\n", sizeof(memory_trace_ent_t), sizeof(memory_trace));
+       printf("size of CREATE3args %d\n", sizeof( CREATE3args));
+       printf("size of MKDIR3args %d\n", sizeof( MKDIR3args));
+       printf("size of READ3args %d\n", sizeof( READ3args));
+       printf("size of WRITE3args %d\n", sizeof( WRITE3args));
+       printf("size of RENAME3args %d\n", sizeof( RENAME3args));
+       printf("size of GETATTR3args %d\n", sizeof( GETATTR3args));
+       printf("size of SETATTR3args %d\n", sizeof( SETATTR3args));
+       printf("size of LINK3args %d\n", sizeof( LINK3args));
+       printf("size of SYMLINK3args %d\n", sizeof( SYMLINK3args));
+       printf("size of MKNOD3args %d\n", sizeof( MKNOD3args));
+       printf("size of RMDIR3args %d\n", sizeof( RMDIR3args));
+       printf("size of REMOVE3args %d\n", sizeof( REMOVE3args));
+       printf("size of LOOKUP3args %d\n", sizeof( LOOKUP3args));
+       printf("size of READDIR3args %d\n", sizeof( READDIR3args));
+       printf("size of READDIRPLUS3args %d\n", sizeof( READDIRPLUS3args));
+       printf("size of FSSTAT3args %d\n", sizeof( FSSTAT3args));
+       printf("size of FSINFO3args %d\n", sizeof( FSINFO3args));
+       printf("size of COMMIT3args %d\n", sizeof( COMMIT3args));
+       printf("size of ACCESS3args %d\n", sizeof( ACCESS3args));
+       printf("size of READLINK3args %d\n", sizeof( READLINK3args));
+
+
+}
+
+void recv_thread()
+{
+       int last_print_time = -1;
+       int busy_flag;
+
+       while (send_num ==0) {
+               usleep(1000);
+       }
+
+       //while (!CYCLIC_EMPTY(dep_tab_index)) {
+       while (!exit_flag) {
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       static int recv_num_before_10_seconds = 0;
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, "<<<<< recv_thread recv_num %d time %d num_out_reqs %d \n", recv_num, total_profile.in.tv_sec, num_out_reqs);
+                       if (recv_num == recv_num_before_10_seconds) {
+                               no_progress_flag = 1;
+                               RFS_ASSERT (0);
+                       } else 
+                               recv_num_before_10_seconds = recv_num;
+               }
+               //start_profile (&check_timeout_profile);
+               check_timeout();
+               //end_profile (&check_timeout_profile);
+
+               pthread_yield();
+               //usleep(1000);
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1) {
+                       busy_flag = BUSY;
+               }
+#endif
+               end_profile (&receive_next_reply_profile);
+       }
+       printf ("<<<< recv thread EXIT\n");
+       exit_flag = 2;
+}
+
+int io_thread ()
+{
+/* number of seconds the I/O thread pauses after each time trying to read the requests */
+#define IO_THREAD_PAUSE_TIME 1
+
+       int i;
+       int j = 0;
+
+       disk_io_status = read_trace ();
+       while (disk_io_status == TRACE_BUF_FULL) {
+
+               usleep (10000);
+        if ((j++%1000)==0) {
+                printf("&&&&&&&&&& io thread, sleep %d seconds\n", j/100);
+        }
+
+               disk_io_status = read_trace ();
+               //printf ("io_thread, after read_trace, disk_index %d\n", disk_index);
+
+#ifdef SEQUEN_READ
+               for (i=0; i<SEQUEN_READ_NUM; i++) {
+                       add_to_dep_tab(CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size));
+               }
+#endif
+               //printf ("***************** IO THREAD SLEEP 1 s\n");
+               //print_cyclic_buffers();
+               //pthread_yield();
+       }
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       printf("io_thread EXIT\n");
+}
+
+int execute_thread()
+{
+       int i;
+       struct timeval playstart_time, playend_time;
+
+       sleep (10);             /* first let io_thread to run for a while */
+       printf ("trace_play\n");
+
+       gettimeofday(&playstart_time, NULL);
+
+       init_time_offset();
+       trace_play ();
+
+       gettimeofday(&playend_time, NULL);
+
+       {
+               int usec, sec;
+               sec = playend_time.tv_sec - playstart_time.tv_sec;
+               usec = sec * 1000000 + (playend_time.tv_usec - playstart_time.tv_usec);
+               sec = usec / 1000000;
+               usec = usec % 1000000;
+               printf("Total play time: %d sec %d usec\n", sec, usec);
+               if (sec > WARMUP_TIME)
+                       print_result();
+               else
+                       printf ("the trace play time %d is less than WARMUP_TIME %d, no statistical results\n");
+       }
+#ifdef RECV_THREAD
+       exit_flag = 1;
+       while (exit_flag == 1) {
+               usleep (1000);
+       }
+#endif
+
+    clnt_destroy(NFS_client);
+    biod_term();
+}
+
+int init_thread ()
+{
+       pthread_attr_t  attr;
+       int arg;
+       int ret = 0;
+       pthread_t io_thread_var;
+#ifdef RECV_THREAD
+       pthread_t recv_thread_var;
+#endif
+       pthread_t execute_thread_var;
+
+       ret = pthread_attr_init (&attr);
+       if (ret!=0) {
+               perror("pthread_attr_init attr");
+               return ret;
+       }
+#ifdef IO_THREAD
+       ret = pthread_create (&(io_thread_var), &attr, &io_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+#ifdef RECV_THREAD
+       ret = pthread_create (&(recv_thread_var), &attr, &recv_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("recv_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+/*
+       ret = pthread_create (&(execute_thread_var), &attr, &execute_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+*/
+}
+
+void init_buffers()
+{
+       CYCLIC_INIT("memory_trace_index",memory_trace_index,MAX_MEMORY_TRACE_LINES);
+       CYCLIC_INIT("dep_tab_index     ",dep_tab_index,DEP_TAB_SIZE);
+       CYCLIC_INIT("dep_window_index  ",dep_window_index,DEP_TAB_SIZE);
+}
+
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       int i;
+       struct timeval in={1000000, 100};
+       
+       init_profile_variables();
+       if ((argc==1) || (argc==2 && !strcmp(argv[1],"-help"))) {
+               print_usage(0, argc, argv);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_write")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_write(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_trace")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_trace(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_aging")) {
+               if (argc!=3) {
+                       print_usage(3, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               check_aging (trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_statistics")) {
+               if (argc!=3) {
+                       print_usage(1, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               memset(fh_htable, 0, sizeof (fh_htable));
+               check_statistics (trace_file);
+               exit(0);
+       }
+
+       if (argc!=6) {
+               print_usage(2, argc, argv);
+               exit(0);
+       }
+
+       PLAY_SCALE = atoi (argv[4]);
+       RFS_ASSERT (PLAY_SCALE >=1 && PLAY_SCALE <=10000);
+
+       WARMUP_TIME = atoi (argv[5]);
+       RFS_ASSERT (WARMUP_TIME >=0 && WARMUP_TIME <=1000);
+       
+       print_memory_usage();
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_semaphores();
+       init_file_system ();
+       init_signal();
+       init_play (argv[1]);
+       //init_play ("capella:/p5/RFSFS");
+       init_fh_map();
+       read_fh_map (argv[3]);
+       //read_fh_map ("fh-path-map-play");
+       strcpy(trace_file, argv[2]);
+
+/* If ordered by TIMESTAMP,
+ * memory_trace_index.tail <= dep_tab_index.tail < dep_window_max <=
+ * dep_tab_index.head <= memory_trace_index.head
+ */
+
+       init_global_variables();
+       init_buffers();
+       init_thread();
+       pthread_yield();
+       execute_thread();
+}
+
+int init_global_variables()
+{
+       memset (num_out_reqs_statistics, 0, sizeof(num_out_reqs_statistics));
+       memset (num_out_reqs_statistics_at_timeout, 0, sizeof(num_out_reqs_statistics_at_timeout));
+}
+
+int init_semaphores()
+{
+       async_rpc_sem = dest_and_init_sem (ASYNC_RPC_SEM_KEY, 1, "async_rpc_sem");
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+}
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+void inline format_line (char * line_before, char * line)
+{
+       char * pv = line_before;
+       char * pl = line;
+       char * p;
+       int i;
+       
+       //printf("format_line before %s\n", line_before);
+       p = strstr (pv, "fh");
+       while (p!=NULL) {
+               while (pv<=p)
+                       *pl++ = *pv++;
+               *pl++ = *pv++;
+               if (*pv==2) {
+                       *pl++ = *pv++;
+               }
+               *pl++ = *pv++;
+               i = 0;
+               while (*pv !=' ') {
+                       RFS_ASSERT ((*pv >='0' && *pv <='9') || (*pv >='a' && *pv<='f'));
+                       *pl++ = *pv++;
+                       i++;
+               }
+               RFS_ASSERT ((i==48) || (i==40) || (i==24));
+               while (i<48) {
+                       *pl++ = '0';
+                       i++;
+               }
+               p = strstr (pv, "fh");
+       }
+       while ((*pv)!=NULL) {
+               *pl++ = *pv++;
+       }
+       //printf("format_line after %s\n", line);
+}
+
+char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+       static int varfh_flag = 0;
+#define READ_LINE_BUF_SIZE (MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR+2)
+#define SAFE_BYTES 1000
+#define READ_LINE_LENGTH (MAX_TRACE_LINE_LENGTH+SAFE_BYTES)
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       char varfh_line_buf[READ_LINE_LENGTH];
+
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+
+                       if (strstr(trace_file, ".varfh")) {
+                               varfh_flag = 1;
+                       };
+                       if (strstr(trace_file, ".fmt1")) {
+                               TRACE_COMMAND_REPLY_FLAG_POS += 12;
+                               TRACE_VERSION_POS +=12;
+                               TRACE_MSGID_POS +=12;
+                               TRACE_FH_SIZE =48;
+                       }
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (varfh_flag) {
+                               if (!fgets(varfh_line_buf, READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                               format_line (varfh_line_buf, line_buf[i]);
+                       } else {
+                               if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       if (disk_index > start_disk_index+READ_LINE_BUF_SIZE) {
+               printf ("disk_index %d start_disk_index %d READ_LINE_BUF_SIZE %d\n", 
+                       disk_index, start_disk_index, READ_LINE_BUF_SIZE);
+       }
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+/*
+       if (!(strlen(line_buf[i])>80)) {
+               printf ("start %d start_disk_index %d disk_index %d strlen %d line_buf[%d] %s\n", start, start_disk_index, disk_index, strlen(line_buf[i]), i, line_buf[i]);
+               RFS_ASSERT (strlen(line_buf[i])>80);
+       }
+       if (!((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH)))
+               printf ("disk_index %d strlen %d line_buf[%d] %s\n", disk_index, strlen(line_buf[i]), i, line_buf[i]);
+       RFS_ASSERT ((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH));
+*/
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+#define OPS_FLAG_INC 0
+#define OPS_FLAG_PRINT 1
+int read_write_fh_statistics (int flag, char * buf, int timestamp)
+{
+       static FILE * fp = NULL;
+       char * p;
+       char c;
+       if (!fp) {
+               fp = fopen ("read_write_fh.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (buf, "fh");
+               RFS_ASSERT (p);
+               c = p[40+3];
+               p[40+3]=0;
+               fprintf(fp, "%s\n", p+3+24);
+               p[40+3]=c;
+       };
+       if (flag == OPS_FLAG_PRINT) { 
+               int disk_index = (int) buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+int write_statistics(int flag, char * buf, char * reply_buf, int trace_status)
+{
+       static FILE * fp = NULL;
+       int pre_size, size, count;
+       char * p = reply_buf;
+       if (!fp) {
+               fp = fopen ("write.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (p, "pre-size");
+               RFS_ASSERT (p);
+               sscanf (p, "pre-size %x", &pre_size); 
+               p += strlen("pre-size");
+               p = strstr (p, "size");
+               RFS_ASSERT (p);
+               sscanf (p, "size %x", &size); 
+               p = strstr (p, "count");
+               if (!p) 
+                       fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+               RFS_ASSERT (p);
+               sscanf (p, "count %x", &count); 
+               fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+       }
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = (int) buf;
+               int timestamp = (int) reply_buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+void ops_statistics (int ops_flag, int proc, int timestamp)
+{
+       static FILE * fp = NULL;
+       static struct {
+               int count;
+               int count_K;
+               int update_flag;
+               char name[32];
+       } ops[NOPS]={{0, 0, 0, "NULL"},{0, 0, 0, "GETATTR"},{0, 0, 1, "SETATTR"},{0, 0, 0, "ROOT"},
+                                 {0, 0, 0, "LOOKUP"},{0, 0, 0, "READLINK"},{0, 0, 0, "READ"},{0, 0, 1, "WRCACHE"},
+                                 {0, 0, 1, "WRITE"}, {0, 0, 1, "CREATE"},{0, 0, 1, "REMOVE"},{0, 0, 1, "RENAME"},
+                                 {0, 0, 1, "LINK"}, {0, 0, 1, "SYMLINK"},{0, 0, 1, "MKDIR"},{0, 0, 1, "RMDIR"},
+                                 {0, 0, 0, "READDIR"},{0, 0, 0, "FSSTAT"},{0, 0, 0, "ACCESS"},{0, 0, 0, "COMMIT"},
+                                 {0, 0, 0, "FSINFO"},{0, 0, 1, "MKNOD"}, {0, 0, 0, "PATHCONF"}, {0, 0, 0, "READDIRPLUS"}};
+
+       if (ops_flag == OPS_FLAG_INC) {
+               RFS_ASSERT (proc>=0 && proc<NOPS);
+               ops[proc].count ++;
+               if (ops[proc].count == 1000) {
+                       ops[proc].count_K ++;
+                       ops[proc].count = 0;
+               }
+       }
+       if (ops_flag == OPS_FLAG_PRINT) {
+               int i;
+               int update_K=0, update=0, total_K=0, total=0;
+               float f1, f2;
+               int disk_index = proc;
+
+               if (!fp) {
+                       fp = fopen ("mix.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               for (i=0; i<NOPS; i++) {
+                       total_K += ops[i].count_K;
+                       total += ops[i].count;
+                       if (ops[i].update_flag) {
+                               update_K += ops[i].count_K;
+                               update += ops[i].count;
+                       }
+               }
+               update_K += update/1000;
+               update = update%1000;
+               total_K += total/1000;
+               total = total%1000;
+
+               f1 = total_K;
+               f1 = f1*1000+total;
+               for (i=0; i<NOPS; i++) {
+                       f2 = ops[i].count_K;
+                       f2 = f2*1000+ops[i].count;
+                       fprintf (fp, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);  
+                       fprintf (stderr, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);      
+               }
+               f2 = update_K;
+               f2 = f2*1000+update;
+               fprintf (fp, "       total %8d,%03d\n", total_K, total);
+               fprintf (stderr, "       total %8d,%03d\n", total_K, total);
+               fprintf (fp, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);   
+               fprintf (stderr, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);       
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+               fprintf(stderr, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+
+void truncate_statistics (int flag, int proc, char * buf, char * reply_buf) 
+{
+#define TRACE_FH_SIZE2 16
+#define BLOCK_SIZE 4096
+       static int no_size_num = 0;
+       static int have_size_num = 0;
+       static int equal_size_num = 0;
+       static int first_size_num = 0;
+       static int truncate_num = 0;
+       static int truncate_size = 0;
+       static int truncate_KB = 0;
+       static int truncate_block_num = 0;
+       static int padding_num = 0;
+       static int padding_KB = 0;
+       static int padding_size = 0;
+       static FILE * fp = NULL;
+       char * p;
+       char * trace_fh;
+       int pre_size, size, count;
+       struct generic_entry * ent;
+
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = proc;
+               int timestamp = (int)buf;
+               if (!fp) {
+                       fp = fopen ("truncate.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               truncate_KB += truncate_size/1000;
+               truncate_size %= 1000;
+               padding_KB += padding_size/1000;
+               padding_size %= 1000;
+               fprintf(fp, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               fprintf(stderr, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               return;
+       }
+
+       p = strstr (&buf[TRACE_MSGID_POS], "fh");
+       RFS_ASSERT (p);
+       p+=3; 
+       trace_fh = p;
+               
+       if (proc==SETATTR) {
+               p = strstr (buf, " size ");
+       } else {
+               RFS_ASSERT (proc==WRITE);
+               p = strstr (reply_buf, " ftype 1 ");
+               RFS_ASSERT (p);
+               p = strstr (p, " size ");
+               RFS_ASSERT (p);
+               if (strstr(p, " ftype 1 ")) {
+                       fprintf (fp, "#### %s%s\n", buf, reply_buf);
+                       fprintf (stderr, "#### %s%s\n", buf, reply_buf);
+               }
+               RFS_ASSERT (!strstr(p, " ftype 1 "));
+       }
+       if (!p) {
+               no_size_num ++;
+               return;
+       }
+       have_size_num ++;
+
+       sscanf (p, " size %x", &size); 
+       if (size <0 || size > 2000000000) {
+               fprintf (fp, "#### size too big %x %s %s\n", size, buf, reply_buf);
+               fprintf (stderr, "#### size too big %x %s %s\n", size, buf, reply_buf);
+       }
+                                                       
+       RFS_ASSERT (size >=0 && size <2000000000);              
+       ent = generic_lookup (trace_fh+24, TRACE_FH_SIZE2, 0, fh_htable, FH_HTABLE_SIZE);
+       if (ent) {
+               if (ent->key3 != size) {
+                       if (proc==SETATTR) {
+                               //printf ("%s\n", buf);
+                               //printf ("size change fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                               if (ent->key3 > size) {
+                                       truncate_num ++;
+                                       truncate_size += ent->key3 - size;
+                                       truncate_block_num += (ent->key3+BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       if (size!=0) {
+                                               //fprintf (stderr, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               //fprintf (fp, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               truncate_block_num -= (size + BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       }
+                                       if (truncate_size > 1000000000) {
+                                               truncate_KB += truncate_size/1000;
+                                               truncate_size %= 1000;
+                                       }
+                               } else {
+                                       padding_num ++; 
+                                       //printf ("%s\n", buf);
+                                       //printf ("padding fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                                       padding_size += size - ent->key3;
+                                       if (padding_size > 1000000000) {
+                                               padding_KB += padding_size/1000;
+                                               padding_size %= 1000;
+                                       }
+                               }
+                       }
+                       ent->key3 = size; 
+               }else 
+                       equal_size_num++;
+       } else {
+               generic_insert(trace_fh+24, TRACE_FH_SIZE2, size, fh_htable, FH_HTABLE_SIZE);
+               first_size_num ++;
+       }
+};
+
+int get_timestamp_usec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       RFS_ASSERT (str[17]==' ');
+       str[17]=0;
+       ret = atoi(&str[11]);
+       RFS_ASSERT (ret >=0 && ret <=999999);
+       return ret;
+}
+
+int get_timestamp_sec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       str[10]=0;
+       ret = atoi(str);
+       RFS_ASSERT (ret >1000000000 && ret <2000000000);
+       return ret;
+}
+
+int check_aging (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               switch (proc) {
+               int off, count, size;
+               char * t;
+               case CREATE: printf("%s\n", "create"); break;
+               case MKDIR: printf("%s\n", "mkdir"); break;
+               case REMOVE: printf("%s\n", "remove"); break;
+               case RMDIR: printf("%s\n", "rmdir"); break;
+               case WRITE: 
+                       t = buf;
+                       t = strstr (t, "off");
+               RFS_ASSERT (t);
+                   t+=4;
+                       sscanf (t, "%x", &off);
+                       RFS_ASSERT (off>=0 && off<0x7FFFFFFF)
+                       t = strstr (t, "count");
+                   RFS_ASSERT (t);
+                       t+=6;
+                       sscanf (t, "%x", &count);
+                       RFS_ASSERT (count <= 32768);
+                       printf("%s off %x count %x\n", "write", off, count); 
+                       //printf("%s count %x\n", "write", count); 
+                       break;
+               case SETATTR: 
+                       t = strstr (buf, " size ");
+                       if (t) {
+                               sscanf (t, " size %x", &size);
+                               printf ("%s size %x\n", "setattr", size);
+                       }
+               }
+               if ((disk_index%10000)==0) {
+                       fprintf(stderr, "%d disk trace passed\n", disk_index);
+               }
+       };
+
+       fprintf(stderr, "%d disk trace parsed\n", disk_index);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, -1);
+}
+
+
+int check_statistics (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+       static int last_timestamp_sec = -1;
+       int timestamp_sec;
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               timestamp_sec = get_timestamp_sec(buf);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               if (proc!= WRITE && proc!=SETATTR && proc!=READ) {
+                       continue;
+               }
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               if (proc==READ || proc==WRITE) 
+                                                       read_write_fh_statistics (OPS_FLAG_INC, buf, 0);
+                                               if (proc == WRITE)
+                                                       write_statistics (OPS_FLAG_INC, buf, reply_buf, trace_status);
+                                               if (proc==WRITE || proc==SETATTR) 
+                                                       truncate_statistics (OPS_FLAG_INC, proc, buf, reply_buf);
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       //printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if *
+               if ((missing_reply_num > memory_trace_size/10) && (missing_reply_num > 100)) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               if (last_timestamp_sec == -1) {
+                       last_timestamp_sec = timestamp_sec;
+               } else if (timestamp_sec - last_timestamp_sec >=3600) {
+                       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+                       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+                       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+                       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+                       last_timestamp_sec = timestamp_sec;
+               }
+/*
+               if ((memory_trace_size%10000)==0) {
+                       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+                       ops_statistics (OPS_FLAG_PRINT, -1);
+                       truncate_statistics (OPS_FLAG_PRINT, -1, NULL, NULL);
+               }
+*/
+       };
+
+       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+}
+
+
+/* This routine output all the requests, together with their replies */
+int pair_trace (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+       FILE * outputfp;
+       char output_file[1024];
+
+       strcpy (output_file, tracefile);
+       strcat (output_file, ".pair");
+       outputfp = fopen (output_file, "w");
+       RFS_ASSERT (outputfp);
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (disk_index == 258)
+                       f();
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+               fprintf (outputfp, "%s\n", buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       fprintf(outputfp, "%s", reply_buf);
+                                       trace_status = find_reply_status(reply_buf);
+                                       if (debug)
+                                               fprintf(stderr, "reply found trace_status %d\n", find_reply_status(reply_buf));
+                                       break;
+                               };
+               }
+               }
+
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       fprintf (stderr, "%s no reply\n", buf);
+                       fprintf(outputfp, "missing_reply\n");
+                       missing_reply_num ++;
+               }
+
+               if (missing_reply_num > memory_trace_size/10 && missing_reply_num >100) {
+                       fprintf (stderr, "missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+
+               memory_trace_size ++;
+
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+/* This routine output all the write requests, together with their replies. It is used for
+ * analysis of write requests: appended bytes, overwrite bytes etc
+ */
+int pair_write (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int pair_write_debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               if (!strstr(buf, "write")) 
+                       continue;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (pair_write_debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               /* store the request to memory */
+               //strcpy (memory_trace[memory_trace_size].line, buf);
+               //memory_trace[memory_trace_size].disk_index = disk_index;
+
+               /* find and store the reply status and reply fhandle to memory */
+               //memory_trace[memory_trace_size].trace_status = NFS3ERR_RFS_MISS;
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (pair_write_debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       int pre_size, size, count;
+                               //memory_trace[memory_trace_size].trace_status = find_reply_status(reply_buf);
+                                       if (pair_write_debug)
+                                               printf("reply found trace_status %d\n", find_reply_status(reply_buf));
+                                               //break;
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               p = strstr (p, "pre-size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "pre-size %x", &pre_size); 
+                                               p += strlen("pre-size");
+                                               p = strstr (p, "size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "size %x", &size); 
+                                               p = strstr (p, "count");
+                                               if (!p) 
+                                                       printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "count %x", &count); 
+                                               printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               break;
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if (missing_reply_num > memory_trace_size/10) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               /*
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               */
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+
+#ifdef notdef
+/* This function is not finished writing */
+int calculate_performance()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+
+typedef struct {
+       struct timeval start;
+       struct timeval stop;
+       int trace_status;
+       int op;
+} trace_performance_ent_t;
+
+       struct timeval req_time;
+       struct timeval reply_time;
+
+       trace_performance_ent_t * ent = NULL;
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+
+               get_timestamp (&ent->req_time, buf);
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               get_timestamp (&ent->reply_time, buf);
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               }
+       }
+}
+#endif
+
+int read_trace ()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+       memory_trace_ent_t * ent=NULL;
+
+       start_profile (&read_trace_profile);
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+       
+               if (rfs_debug)
+                       printf ("disk_index %d %s\n", disk_index, buf);
+
+               if (disk_index==0) {
+                       trace_timestamp1 = get_timestamp_sec (buf);
+                       trace_starttime.sec = get_timestamp_sec (buf);
+                       trace_starttime.usec = get_timestamp_usec (buf);
+                       trace_starttime.esec = 0;
+                       printf ("trace starttime %d %d %d\n", trace_starttime.sec, trace_starttime.usec, trace_starttime.esec);
+               } else
+                       trace_timestamp2 = get_timestamp_sec (buf);
+
+               /* store the request to memory */
+               ent = &(memory_trace[memory_trace_index.head]);
+               strcpy (ent->line, buf);
+               ent->disk_index = disk_index;
+
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               };
+
+               if (ent->trace_status == NFS3ERR_RFS_MISS)
+                       missing_reply_num ++;
+
+               if (MAX_COMMAND_REPLY_DISTANCE > 1) {
+                       if ((missing_reply_num > disk_index/5) && (missing_reply_num > 100)) {
+                               printf ("missing_reply_num %d too high for disk_index %d\n", missing_reply_num, disk_index);
+                               exit (0);
+                       }
+               }
+
+               /* find and store the reply trace fhandle for create-class requests */
+               if (ent->trace_status==NFS3_OK) {
+                       if (strstr(buf, "create") || strstr(buf, "mkdir") 
+                               || (strstr(buf, "symlink") && (buf[TRACE_VERSION_POS]!='2')) 
+                               || strstr(buf, "mknod") ) {
+                               p = find_reply_trace_fh(reply_buf);
+                               if (p==NULL) {
+                                       printf("skip line disk_index %d %s \n", disk_index, buf);
+                                       continue;
+                               }
+                               memcpy(ent->reply_trace_fh, p, TRACE_FH_SIZE);
+                       } else
+                               memset(ent->reply_trace_fh, 0, TRACE_FH_SIZE);
+               }
+
+               add_to_dep_tab(memory_trace_index.head);
+
+               if (((disk_index+1)%20000)==0) {
+                       fprintf(stderr, "%d disk trace parsed \n", disk_index+1);
+               };
+       };
+
+       end_profile (&read_trace_profile);
+       return TRACE_BUF_FULL;
+}
+#else  /* not defined REDUCE_MEMORY_TRACE_SIZE */
+int read_trace ()
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(trace_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, MAX_TRACE_LINE_LENGTH, fp)) {
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+               /* store the request to memory */
+               strcpy (memory_trace[memory_trace_size].line, buf);
+               memory_trace[memory_trace_size].disk_index = disk_index;
+               memory_trace_size ++;
+
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               if ((disk_index%100000)==0)
+                       fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+               disk_index ++;
+       }
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+}
+#endif
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+
+       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index));
+       RFS_ASSERT (memory_trace[memory_trace_index.tail].disk_index <= disk_index);
+       RFS_ASSERT (memory_trace[CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size)].disk_index >=disk_index);
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index = CYCLIC_ADD(memory_index,1,memory_trace_index.size);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index = CYCLIC_MINUS(memory_index,1,memory_trace_index.size);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       if (rfs_debug)
+               printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       if (!(line[TRACE_COMMAND_REPLY_FLAG_POS]=='R')) {
+               printf ("disk_index %d %s\n", disk_index, line);
+       };
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       p = line+TRACE_MSGID_POS+2;     /* at least one letter for msgid and one letter for space */
+       if (strstr(p, "OK"))
+               return NFS3_OK;
+       if (strstr(p, "lookup 2") || strstr(p, "lookup   2"))
+               return 0x2;
+       if (strstr(p, "create d"))
+               return 0xd;
+       if (strstr(p, "setattr 1"))
+               return 0x1;
+       if (strstr(p, "setattr 2712")) /* 10002 NFS3ERR_NOT_SYNC */
+               return 0x2712;
+       if (strstr(p, "lookup d"))
+               return 0xd;
+       if (strstr(p, "read d"))
+               return 0xd;
+       if (strstr(p, "write d"))
+               return 0xd;
+       if (strstr(p, "write 46"))
+               return 0x46;
+       if (strstr(p, "getattr 46"))
+               return 0x46;
+       if (strstr(p, "mkdir d"))
+               return 0xd;
+       printf ("line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       printf ("!!!!!!!!!!!!!!!!!!!!!!!!\n");
+       fprintf (stderr, "line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       fprintf (stderr, "!!!!!!!!!!!!!!!!!!!!!!!!\n");
+}
+
+inline int find_reply_status_old (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p) {
+               printf ("disk_index %d find_reply_trace_fh line %s\n", disk_index, line);
+               return NULL;
+       } else
+               return p+6;
+}
+
+#ifndef NO_DEPENDENCY_TABLE
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+#endif
+
+inline int is_play_candidate (int dep_index)
+{
+       int proc = dep_tab[dep_index].proc;
+       int status = dep_tab[dep_index].status;
+       int trace_status = dep_tab[dep_index].trace_status;
+
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       /* for a failed create in trace, trace_replay just ignore many time the trace create fail
+        * due to access control, but trace_play will success because our access control
+        * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+        */
+       if ((proc==CREATE || proc==MKDIR) && (trace_status!=NFS3_OK) && (status!=NFS3ERR_RFS_MISS)) {
+               if (dependency_debug)
+                       printf ("disk[%d] ignore failed create/mkdir in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               failed_create_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_OTHER_FAILED_COMMAND
+       if (((trace_status == NFS3ERR_ACCES) && (proc==READ || proc==WRITE || proc==LOOKUP)) || 
+           ((trace_status == NFS3ERR_PERM) && (proc==SETATTR))                                                                         ){
+               if (dependency_debug)
+                       printf ("disk[%d] ignore other failed command in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               
+               failed_other_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK) ) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+/* This is actually take care in get_nextop by checking fh_map error when dep_index==min_dep_index */
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+/*
+       if ((    ((dep_tab[dep_index].disk_index==262213) || (dep_tab[dep_index].disk_index==214402))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1100.txt")) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+*/
+       if ((    ((dep_tab[dep_index].disk_index==423727) || (0))
+                 && !(strncmp(trace_file, "anon-lair62-011130-1500.txt", strlen("anon-lair62-011130-1500.txt"))) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+       /* this line is about the mkdir 116d9d originally in anon-lair62-011130-1400.txt */
+       if (!strncmp(dep_tab[dep_index].line, "1007147245.194201", strlen("1007147245.194201"))) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_FSSTAT_COMMAND
+       /* the file handle used in this command is not processed properly by pre-processing */
+       if (proc==FSSTAT) {
+               char * trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+               fh_map_t * fh = lookup_fh (trace_fh);
+               if (!fh) {
+                       skipped_fsstat_command_num++;
+                       return FALSE;
+               }
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+static inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+#define INIT_MIN_WAIT_VALUE -999
+       static int min_wait_fhandle_dep_index = INIT_MIN_WAIT_VALUE;
+       int proc;
+       int flag;
+
+       if (min_wait_fhandle_dep_index == -999)
+               min_wait_fhandle_dep_index = dep_window_index.head;
+
+       for (i=0; i<CYCLIC_NUM(dep_window_index); i++) {
+               dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (CYCLIC_LESS(dep_tab_index,dep_index,min_wait_fhandle_dep_index)) 
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       if (dep_index==dep_window_index.tail) {
+                                               if (!profile_debug) 
+                                                       printf ("fh_path_map error disk[%d] state DEP_FLAG_WAIT_FHANDLE to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                                               fh_path_map_err_num ++;
+                                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                                               continue;
+                                       }
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#define DEPENDENCY_TIMEOUT 50
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       if (tmp.sec >= DEPENDENCY_TIMEOUT) {
+                                               printf("dep_tab[%d].flag %d disk_index %d line %s\n", dep_index,
+                                                       dep_tab[dep_index].flag, dep_tab[dep_index].disk_index,
+                                                       dep_tab[dep_index].line);
+                                       }
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_window_index.head;
+                                       for (j=CYCLIC_ADD(dep_index,1,dep_window_index.size); CYCLIC_LESS(dep_window_index,j,dep_window_index.head); j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else /*NO_DEPENDENCY_TABLE undefined */
+       /* this part of code will be invalid after CYCLIC buffer design */
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { 
+                                               /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+       struct ladtime current_time;
+
+       sfs_gettime (&current_time);    
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current_time.sec>timeout.sec) ||
+                               ((current_time.sec==timeout.sec) && (current_time.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_CANDIDATE);
+                               } else {
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_DONE);
+                               }
+                               timeout_num ++;
+                               num_out_reqs_statistics_at_timeout[num_out_reqs]++;
+
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               if (per_packet_debug)
+                                       printf ("timeout request: disk_index %d, dep_index %d biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", dep_tab[dep_index].disk_index, dep_index, biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+               num_out_reqs++;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if ((biod_reqp[biod_index].in_use == TRUE) &&( biod_reqp[biod_index].xid == xid)) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[TRACE_MSGID_POS], "%x %x", &msgid, &nfsproc);
+       //printf ("msgid %x nfsproc %x\n", msgid, nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+}
+
+void adjust_play_window (int flag, int * poll_timeout_arg)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int i;
+       char * line;
+       cyclic_index_t old_dep_window_index = dep_window_index;
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, begin\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("                adjust_play_window, begin\n");
+#endif
+
+       while ((!CYCLIC_EMPTY(dep_window_index)) && (dep_tab[dep_window_index.tail].flag == DEP_FLAG_DONE)) {
+#ifdef notdef
+               //CYCLIC_PRINT (memory_trace_index);
+               //printf("MOVE_TAIL_TO memory_index %d\n", dep_tab[dep_tab_index.tail].memory_index);
+               RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+               RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+               printf("%d is done\n", dep_window_index.tail);
+#endif
+               CYCLIC_MOVE_TAIL(dep_tab_index);
+               CYCLIC_MOVE_TAIL(dep_window_index);
+
+#ifdef notdef
+               CYCLIC_PRINT (dep_tab_index);
+               CYCLIC_PRINT (dep_window_index);
+
+               if (! (dep_tab_index.tail == dep_window_index.tail)) {
+                       CYCLIC_PRINT(dep_tab_index);
+                       CYCLIC_PRINT(dep_window_index);
+               };
+               RFS_ASSERT ( dep_tab_index.tail == dep_window_index.tail);
+#endif
+
+               if (!CYCLIC_EMPTY(dep_tab_index)) {
+#ifdef notdef
+                       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+                       if (!(CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head))) {
+                               CYCLIC_PRINT(memory_trace_index);
+                               CYCLIC_PRINT(dep_tab_index);
+                               printf("dep_tab[head-1].memory_index, %d [tail].memory_index %d\n", 
+                                       dep_tab[CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size)].memory_index,
+                                       dep_tab[dep_tab_index.tail].memory_index);
+                       }
+                       RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+#endif
+                       CYCLIC_SET_TAIL_TO(&memory_trace_index, dep_tab[dep_tab_index.tail].memory_index);
+                       //printf ("set memory_trace_index to %d=%d, dep_tab_index.tail %d\n", memory_trace_index.tail, dep_tab[dep_tab_index.tail].memory_index, dep_tab_index.tail);
+               } else {
+               //      CYCLIC_MOVE_TAIL (memory_trace_index);
+               }
+       }
+
+       while (CYCLIC_EMPTY(dep_tab_index)) {
+               
+               if (disk_io_status == TRACE_FILE_END) 
+                       return;
+               else {
+                       //printf ("************** ADJUST_PLAY_WINDOW sleep 1 s\n"); 
+                       //print_cyclic_buffers();
+                       //pthread_yield();
+                       //usleep (1000);
+               }
+       }
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (CYCLIC_NUM(dep_window_index) == MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, dep_tab_size %d dep_window_max %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", dep_tab_size, dep_window_max, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               struct ladtime t;
+               int dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+        t.sec = dep_tab[dep_index].timestamp.tv_sec;
+        t.usec = dep_tab[dep_index].timestamp.tv_usec;
+               if ((t.sec>max_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec))
+            break;
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout_arg = 0;
+       else if (CYCLIC_NUM(dep_window_index)==CYCLIC_NUM(dep_tab_index)) {
+               *poll_timeout_arg = 1000;       /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_index.head].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_index.head].timestamp.tv_usec;
+               if (adjust_play_window_debug>=2)
+                       printf ("dep_tab[dep_window_index.head %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_index.head, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+/*
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_max, dep_tab[dep_window_max].timestamp.tv_sec, dep_tab[dep_window_max].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+*/
+
+               //RFS_ASSERT ((tmp.sec < 1000));
+               if (tmp.sec > 1000)
+                       tmp.sec = 1000;
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout_arg = 0;
+               } else
+                       *poll_timeout_arg = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_max].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_max].timestamp.tv_usec;
+               tmp1.sec = dep_tab[dep_window_max-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[dep_window_max-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout_arg = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout_arg %d \n", 
+               flag, old_dep_window_index.tail, dep_window_index.tail, old_dep_window_index.head,
+               dep_window_index.head, *poll_timeout_arg);
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, end\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("        adjust_play_window, end\n\n");
+#endif
+       //CYCLIC_ASSERT(4);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+#ifdef RECV_THREAD
+       //printf("recv thread waitsem 1\n");
+       waitsem (async_rpc_sem);
+       //printf("recv thread got sem 1\n");
+#endif
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       //printf("recv thread waitsem 2\n");
+                       //waitsem (async_rpc_sem);
+                       //printf("recv thread got sem 2\n");
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       //postsem (async_rpc_sem);
+                       //printf("recv thread postsem 2\n");
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+#ifdef RECV_THREAD
+       postsem (async_rpc_sem);
+       //printf("recv thread postsem 1\n");
+#endif
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+#if    0       /* commented out by G. Jason Peng */
+       RFS_ASSERT (read_data_owe_GB==0);
+       printf("read_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",read_data_total_GB, read_data_total, read_data_owe_GB, read_data_owe, (read_data_owe)/(read_data_total/100), read_data_adjust_times);
+       printf("write_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",write_data_total_GB, write_data_total, write_data_owe_GB, write_data_owe, (write_data_owe)/(write_data_total/100), write_data_adjust_times);
+       printf("poll_timeout_0_num %d poll_timeout_pos_num %d\n", poll_timeout_0_num, poll_timeout_pos_num);
+       printf("failed_create_command_num_in_original_trace %d\nfailed_other_command_num_in_original_trace %d\nskipped_readlink_command_num %d\nskipped_custom_command_num %d\nfh_path_map_err_num %d\nskipped_fsstat_command_num %d\nmissing_reply_num %d\nrename_rmdir_noent_reply_num %d\nrmdir_not_empty_reply_num %d\nloose_access_control_reply_num %d\nlookup_err_due_to_rename %d\nlookup_err_due_to_parallel_remove %d\nlookup_eaccess_enoent_mismatch %d\nread_io_err_num %d\nstale_fhandle_err_num %d abnormal_EEXIST_num %d abnormal_ENOENT_num %d proper_reply_num %d run_stage_proper_reply_num %d\n", 
+                       failed_create_command_num,
+                       failed_other_command_num,
+                       skipped_readlink_command_num, 
+                       skipped_custom_command_num,
+                       fh_path_map_err_num, 
+                       skipped_fsstat_command_num, 
+                       missing_reply_num, 
+                       rename_rmdir_noent_reply_num, 
+                       rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, 
+                       lookup_err_due_to_rename_num, 
+                       lookup_err_due_to_parallel_remove_num,
+                       lookup_eaccess_enoent_mismatch_num, 
+                       read_io_err_num, 
+                       stale_fhandle_err_num,
+                       abnormal_EEXIST_num,
+                       abnormal_ENOENT_num,
+                       proper_reply_num, run_stage_proper_reply_num);
+#endif
+
+//  print_dump(Client_num, Child_num);
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               //RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               if (memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE)) {
+                       int i;
+                       printf ("fh_map[%d].trace_fh %s trace_fh %s", p->key3, fh_map[p->key3].trace_fh, trace_fh);
+                       for (i=0; i<fh_i; i++) {
+                               int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                               int * p = (int *)fh_map[i].trace_fh;
+                               printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                               printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, fh_map[i].trace_fh, fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+                       }
+#endif
+                       RFS_ASSERT (0);
+               }
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               /* It's possible that in fh-path-map, many trace_fh are corresponding to one path
+                * some of it may be the result of lookup after symlink, which is not handled
+                * properly as new created objects 
+                */
+#ifdef TAKE_CARE_SYMBOLIC_LINK
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+#endif
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       strncpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       //show_fhandle(play_fh);
+               } else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+inline fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i[%d] trace_fh %s path %s play_fh:\n", p->key3, fh_map[p->key3].trace_fh, fh_map[p->key3].path);
+                       //show_fhandle(&fh_map[p->key3].play_fh);
+               }
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+int lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+       return (reply.status);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[MAX_TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+       int lineno = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       if (strstr(fh_map_file, "fmt1")) {
+               TRACE_FH_SIZE = 48;
+       }
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               lineno ++;
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7) ||
+                       !strncmp (trace_path, "LN", 2)                  ) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       int ret = lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);               
+                       if (ret!=NFS3_OK) {
+                               printf ("lineno %d %s\n", lineno, buf);
+                       }
+                       RFS_ASSERT (ret == NFS3_OK);
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline free_biod_req (int biod_index)
+{
+       RFS_ASSERT (biod_reqp[biod_index].in_use == TRUE);
+       biod_reqp[biod_index].in_use = FALSE;
+       num_out_reqs --;
+}
+
+void finish_request (int biod_index, int dep_index, int status, int dep_flag)
+{
+       static int i = 0;
+       /* the ending operation, same as when a request time out */
+
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       free_biod_req (biod_index);
+
+       dep_tab[dep_index].status = status;
+
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = -dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].flag = dep_flag;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+       static int last_print_time = -1;
+
+       if (num_out_reqs == max_biod_reqs) {
+               return -1;
+       }
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+
+       if (per_packet_debug)
+               fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+
+       end_profile(&total_profile);
+       if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+               last_print_time = total_profile.in.tv_sec;
+               //fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+/*
+               CYCLIC_PRINT (dep_tab_index);
+               {
+                       int tmp = CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size);
+                       printf("dep_tab_index.head-1 %d disk_index %d tail %d disk_index %d\n", tmp, dep_tab[tmp].disk_index,
+                       dep_tab_index.tail, dep_tab[dep_tab_index.tail].disk_index);
+               }
+*/
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+/*
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+*/
+#endif
+               if ((total_profile.in.tv_sec > 100)) {
+                       can_not_catch_speed_num_total += can_not_catch_speed_num;
+               }
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+#ifdef notdef  /* place to set request timeout. G. Jason Peng */
+       call_timeout.sec = 2; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+#else
+       call_timeout.sec = 0;
+       call_timeout.usec = 300000;
+       //call_timeout.usec = 14000;
+       //call_timeout.usec = 13000;
+       //call_timeout.usec = 6000;
+       //call_timeout.usec = 8000;
+       //call_timeout.usec = 10000;
+#endif
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+
+#ifdef RECV_THREAD
+       //printf ("send thread waitsem\n");
+       waitsem(async_rpc_sem);
+       //printf ("send thread got sem\n");
+#endif
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#ifdef RECV_THREAD
+       postsem(async_rpc_sem);
+       //printf ("send thread postsem\n");
+#endif
+
+#else  // REAL_PLAY
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    RFS_ASSERT (reqp->xid != 0);
+    reqp->timeout = reqp->start;
+    ADDTIME (reqp->timeout, call_timeout);
+    dep_tab[dep_index].flag = DEP_FLAG_SENT;
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+
+       send_num ++;
+}
+
+void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_status)
+{
+       if (((status!=trace_status)) && (status!=NFS3_OK) && (trace_status!=NFS3ERR_RFS_MISS)) {
+               if (!profile_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else // if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_status == 0)) {
+                               /* trace_status could be EAGAIN */
+                       if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) ) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+               } else if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status == NFS3ERR_NOENT)) {
+                       /* if there is a remove in front of the lookup, but it is
+                        * actually executed later than the lookup
+                        */
+                       lookup_err_due_to_parallel_remove_num ++;
+#endif
+#ifndef TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+               /* if the looked return EACCESS in the trace, means the object still exists
+                * should have initialized, right not don't initialize it, hence play status 
+                * could be ENOENT
+                */
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3ERR_ACCES)) {
+                       lookup_eaccess_enoent_mismatch_num ++;
+#endif
+#ifdef TOLERANT_READ_IO_ERR
+               } else if ((proc==READ) && (status==NFS3ERR_IO) && (trace_status==NFS3_OK)) {
+                       read_io_err_num ++;
+#endif
+#ifdef TOLERANT_STALE_FHANDLE_ERR
+               } else if ((status==NFS3ERR_STALE) && (trace_status==NFS3_OK)) {
+                       printf ("!!!!!!! STALE FILE HANDLE \n");
+                       //sleep(1);
+                       stale_fhandle_err_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=dep_window_index.tail; CYCLIC_LESS(dep_window_index,i,dep_window_index.head); i++) {
+                               if (dep_tab[i].flag!=1)
+                                       printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       }
+
+                       if (status==EEXIST) {
+                               abnormal_EEXIST_num ++;
+                       } else if (status == ENOENT) {
+                               abnormal_ENOENT_num ++;
+                       } else {
+                               printf ("!!!!!!!!!!!!!1 should fail\n");
+                               //RFS_ASSERT (0);
+                       }
+               }
+       } else {
+               proper_reply_num ++;
+               if (total_profile.in.tv_sec >= WARMUP_TIME) 
+                       run_stage_proper_reply_num ++;
+       }
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_status;
+       char * errmsg;
+       int poll_timeout = 0;           /* timeout in usecs */
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+
+       if (busy_flag == BUSY) {
+               poll_timeout = 0;
+               poll_timeout_0_num ++;
+       } else {
+               poll_timeout = 2000;    /* 10000 or 2000 is a better number in non-debugging state */
+               //poll_timeout = 0;     /* 10000 or 2000 is a better number in non-debugging state */
+               poll_timeout_pos_num ++;
+       }
+
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       if (biod_reqp[biod_index].in_use==1) {
+               RFS_ASSERT (dep_tab[dep_index].biod_req_index == biod_index);
+       } else {
+               printf ("biod_index %d reply received but the request has been time out\n", biod_index);
+               return -1;
+       }
+
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = dep_tab[dep_index].reply_line;
+       trace_status = dep_tab[dep_index].trace_status;
+
+       if (per_packet_debug || rfs_debug )
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status, DEP_FLAG_DONE);
+       recv_num ++;
+       
+       /* we set 100 seconds warm up time */
+       if ((total_profile.in.tv_sec >= WARMUP_TIME)) {
+       /* get statistics */
+       if (status == trace_status || (status==NFS3_OK && trace_status==NFS3ERR_RFS_MISS) ) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       }
+       
+       //start_profile (&add_create_object_profile);
+
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+               RFS_ASSERT (reply_line);
+#endif
+               if (status!=NFS3_OK) {
+                       /* commented out for 1022 */
+                       printf ("!!!!!! Should have been an ASSERTION FAILURE \n");
+                       RFS_ASSERT (proc==SYMLINK);
+                       RFS_ASSERT (0);
+               } else {
+                       if (proc!=SYMLINK || line[TRACE_VERSION_POS]!='2')
+                               add_new_file_system_object(proc, dep_index, line, reply_line);
+               }
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+       reply_trace_fh = dep_tab[dep_index].reply_trace_fh;
+#else
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+#endif
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+#endif
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       /* just to preserve the original reply line not changed */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+#endif
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, dep_window_max> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+       static int last_print_time = -1;
+       int poll_timeout = 0;
+
+#ifndef IO_THREAD
+       disk_io_status = read_trace();
+#endif
+
+       RFS_ASSERT (!CYCLIC_EMPTY(dep_tab_index));
+       CYCLIC_MOVE_HEAD(dep_window_index);
+
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while (!CYCLIC_EMPTY(dep_tab_index)) {
+               end_profile(&total_profile);
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       int i;
+
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, ">>>> sendng thread: time %d send_num %d recv_num %d timeout_num %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, send_num, recv_num, timeout_num, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics[i]!=0) {
+                                       printf("num_out_req[%d]=%d,", i, num_out_reqs_statistics[i]);
+                                       num_out_reqs_statistics[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics_at_timeout[i]!=0) {
+                                       printf("num_out_req_at_timeout[%d]=%d,", i, num_out_reqs_statistics_at_timeout[i]);
+                                       num_out_reqs_statistics_at_timeout[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       //      CYCLIC_PRINT(dep_tab_index);
+               }
+
+               if ((total_profile.in.tv_sec > 6000)) {
+                       printf ("the process has run for more than 600 seconds, exit\n");
+                       goto END;
+               }
+
+               if (busy_flag == IDLE) {
+#ifndef RECV_THREAD
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+#endif
+#ifndef IO_THREAD
+                       if (disk_io_status!=TRACE_FILE_END) {
+                               disk_io_status = read_trace();
+                       };
+#endif
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               num_out_reqs_statistics[num_out_reqs]++;
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1) {
+                       busy_flag = BUSY;
+               }
+               end_profile (&execute_next_request_profile);
+
+#ifndef RECV_THREAD
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+#endif
+               end_profile (&receive_next_reply_profile);
+#endif
+               CYCLIC_ASSERT (0);
+       }
+       end_profile (&total_profile);
+
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       if (num_out_reqs !=0 ) {
+               printf ("num_out_reqs %d\n", num_out_reqs);
+               CYCLIC_PRINT(dep_tab_index);
+       }
+       RFS_ASSERT(num_out_reqs==0);
+
+END:
+       printf ("trace starttime %d, trace_end_time %d trace_duration %d\n", trace_timestamp1, trace_timestamp2,
+               trace_timestamp2 - trace_timestamp1);
+       printf ("can_not_catch_speed_num_total %d can_not_catch_speed_num_last_10_seconds %d", 
+               can_not_catch_speed_num_total, can_not_catch_speed_num);
+       printf ("total_profile.about: %s\n", total_profile.about);
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       //print_profile ("check_timeout", &check_timeout_profile);
+       //printf("\n");
+       //print_profile ("adjust_play_window", &adjust_play_window_profile);
+       //printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument_profile", &prepare_argument_profile);
+       print_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply_profile", &decode_reply_profile);
+       print_profile ("check_reply_profile", &check_reply_profile);
+       print_profile ("fgets_profile", &fgets_profile);
+       print_profile ("read_line_profile", &read_line_profile);
+       print_profile ("read_trace_profile", &read_trace_profile);
+       //print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("dep_tab_index.tail %d dep_tab_index.head %d num_out_reqs %d\n", dep_tab_index.tail, dep_tab_index.head, num_out_reqs);
+}
+
+
+int CYCLIC_SET_TAIL_TO(cyclic_index_t * index, int dest) 
+{ 
+       cyclic_index_t indextmp, indextmp2;
+       int oldnum, num;
+       indextmp = *index;
+       indextmp2 = indextmp;
+       oldnum = CYCLIC_NUM(indextmp); 
+
+       if (! ((dest>=0) && (dest<indextmp.size))) {
+               CYCLIC_PRINT(indextmp);
+               printf("dest %d\n", dest);
+       }
+       RFS_ASSERT ((dest>=0) && (dest<indextmp.size));
+       index->tail = dest; 
+       indextmp2.tail = dest;
+       num = CYCLIC_NUM(indextmp2); 
+
+       if (num > oldnum) { 
+               CYCLIC_PRINT(indextmp);
+               CYCLIC_PRINT(indextmp2);
+               printf("dest %d old_num %d num %d\n", dest, oldnum, num);
+       }
+       RFS_ASSERT (num <= oldnum);
+}
+
+int flush_junk()
+{
+       int i;
+       for (i=0; i<500; i++) {
+               printf ("*************************************************************\n");
+       }
+       fflush(stdout);
+}
+
+int CYCLIC_ASSERT (int i)
+{
+       int j;
+       if (!(dep_tab_index.tail == dep_window_index.tail)) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       if (!((dep_window_index.head == dep_tab_index.head) || 
+                  CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ) )) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       for (i=0, j=0; i<max_biod_reqs; i++) {
+               if (biod_reqp[i].in_use == 1)
+                       j++;
+       }
+#ifndef RECV_THREAD
+       RFS_ASSERT (num_out_reqs==j);
+#endif
+/*
+               RFS_ASSERT ((dep_window_index.head == dep_tab_index.head) || 
+                          CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ));
+*/
+}
+
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_chd.c b/TBBT/trace_play/sfs_c_chd.c
new file mode 120000 (symlink)
index 0000000..0c356df
--- /dev/null
@@ -0,0 +1 @@
+sfs_c_chd.3thread.c
\ No newline at end of file
diff --git a/TBBT/trace_play/sfs_c_chd.c.old b/TBBT/trace_play/sfs_c_chd.c.old
new file mode 100644 (file)
index 0000000..1d2f423
--- /dev/null
@@ -0,0 +1,2457 @@
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static void read_trace(char * trace_file);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+static void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+static void adjust_play_window (int flag, int * poll_timeout);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern inline fh_map_t * lookup_fh (char * trace_fh );
+static inline void finish_request (int biod_index, int dep_index, int status);
+static inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+static inline char * find_lead_trace_fh(int proc, char * line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+void print_usage()
+{
+       printf("sfs3 hostname:mount_dir trace_file fh_map_file\n");
+       exit;
+}
+
+void read_dep_tab()
+{
+#ifdef NO_DEPENDENCY_TABLE
+       int i;
+       char * line;
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       int req_num_with_new_fh = 0;
+       int     req_num_with_discard_fh = 0;
+       int req_num_with_init_fh =0;
+
+       for (i=0; i<memory_trace_size; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='C') {
+                       trace_fh = strstr (line, "fh");
+                       RFS_ASSERT (trace_fh);
+                       trace_fh += 3;
+                       fh_map_entry = lookup_fh (trace_fh);
+                       if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+                               req_num_with_discard_fh ++;
+                               continue;
+                       }
+                       if (fh_map_entry)
+                               req_num_with_init_fh ++;
+                       else
+                               req_num_with_new_fh ++;
+
+                       dep_tab[dep_tab_size].disk_index = memory_trace[i].disk_index;
+                       dep_tab[dep_tab_size].line = memory_trace[i].line;
+                       if ((dep_tab_size%100000)==0)
+                               printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_size, dep_tab[dep_tab_size].disk_index, i, memory_trace[i].disk_index);
+                       dep_tab_size ++;
+               }
+       }
+#else
+       RFS_ASSERT (0);
+#endif
+       printf ("read_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+}
+
+void init_profile()
+{
+       memset (&total_profile, 0, sizeof(total_profile));
+
+       memset (&execute_next_request_profile, 0, sizeof(execute_next_request_profile));
+       memset (&valid_get_nextop_profile, 0, sizeof(valid_get_nextop_profile));
+       memset (&invalid_get_nextop_profile, 0, sizeof(invalid_get_nextop_profile));
+       memset (&prepare_argument_profile, 0, sizeof(prepare_argument_profile));
+       memset (&biod_clnt_call_profile, 0, sizeof(biod_clnt_call_profile));
+
+       memset (&receive_next_reply_profile, 0, sizeof(receive_next_reply_profile));
+       memset (&valid_poll_and_get_reply_profile, 0, sizeof(valid_poll_and_get_reply_profile));
+       memset (&invalid_poll_and_get_reply_profile, 0, sizeof(invalid_poll_and_get_reply_profile));
+       memset (&decode_reply_profile, 0, sizeof(decode_reply_profile));
+       memset (&check_reply_profile, 0, sizeof(check_reply_profile));
+       memset (&add_create_object_profile, 0, sizeof(add_create_object_profile));
+
+       memset (&check_timeout_profile, 0, sizeof(check_timeout_profile));
+       memset (&adjust_play_window_profile, 0, sizeof(adjust_play_window_profile));
+}
+
+static char trace_file[256]="anon-lair62-011130-1200.txt";
+int print_memory_usage()
+{
+       printf("size of fh_map_t %d size of fh_map %d\n", sizeof(fh_map_t), sizeof(fh_map));
+       printf("sizeof dep_tab_t %d sizeof dep_tab %d\n", sizeof(dep_tab_t), sizeof(dep_tab));
+       printf("size of memory_trace_entry_t %d sizeof memory_trace %d\n", sizeof(memory_trace_entry_t), sizeof(memory_trace));
+       printf("size of CREATE3args %d\n", sizeof( CREATE3args));
+       printf("size of MKDIR3args %d\n", sizeof( MKDIR3args));
+       printf("size of READ3args %d\n", sizeof( READ3args));
+       printf("size of WRITE3args %d\n", sizeof( WRITE3args));
+       printf("size of RENAME3args %d\n", sizeof( RENAME3args));
+       printf("size of GETATTR3args %d\n", sizeof( GETATTR3args));
+       printf("size of SETATTR3args %d\n", sizeof( SETATTR3args));
+       printf("size of LINK3args %d\n", sizeof( LINK3args));
+       printf("size of SYMLINK3args %d\n", sizeof( SYMLINK3args));
+       printf("size of MKNOD3args %d\n", sizeof( MKNOD3args));
+       printf("size of RMDIR3args %d\n", sizeof( RMDIR3args));
+       printf("size of REMOVE3args %d\n", sizeof( REMOVE3args));
+       printf("size of LOOKUP3args %d\n", sizeof( LOOKUP3args));
+       printf("size of READDIR3args %d\n", sizeof( READDIR3args));
+       printf("size of READDIRPLUS3args %d\n", sizeof( READDIRPLUS3args));
+       printf("size of FSSTAT3args %d\n", sizeof( FSSTAT3args));
+       printf("size of FSINFO3args %d\n", sizeof( FSINFO3args));
+       printf("size of COMMIT3args %d\n", sizeof( COMMIT3args));
+       printf("size of ACCESS3args %d\n", sizeof( ACCESS3args));
+       printf("size of READLINK3args %d\n", sizeof( READLINK3args));
+
+
+}
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       int i;
+       int memory_trace_size;
+
+       if (argc==2 && !strcmp(argv[1],"-help")) {
+               print_usage();
+               exit(0);
+       }
+       print_memory_usage();
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_file_system ();
+
+       init_signal();
+       init_play (argv[1]);
+       //init_play ("capella:/p5/RFSFS");
+       init_profile();
+       init_fh_map();
+       //read_fh_map (argv[3]);
+       read_fh_map ("fh-path-map-play");
+       init_dep_tab();                 /* and  dep_tab_size */
+       //read_trace (argv[2]);
+       //read_trace ("anon-lair62-011130-1000.txt");
+       strcpy(trace_file, argv[2]);
+       read_trace (trace_file);
+       stage = READ_DEP_TAB_STAGE;
+       read_dep_tab();
+
+       for (i=0; i<dep_tab_size; i++) {
+               RFS_ASSERT (dep_tab[i].flag == DEP_FLAG_FREE) 
+               init_dep_tab_entry (i);
+       }
+       stage = TRACE_PLAY_STAGE;
+       init_time_offset();
+       printf ("trace_play\n");
+       trace_play ();
+       print_result();
+       printf("ffff\n");
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+       
+
+}
+
+void read_trace (char * tracefile)
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(tracefile, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, 1024, fp)) {
+               //printf ("buf: %s buf[36] %c\n", buf, buf[36]);
+               //if (buf[36]=='C' || strstr(buf, "create") || strstr(buf, "lookup")) {
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]=='C' || strstr(buf, "create") || 
+                       strstr(buf, "mkdir") || strstr(buf, "symlink") || strstr(buf, "mknod") || strstr(buf, "lookup")) {
+#endif
+                       if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                               printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+                       RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+                       /* store the request to memory */
+                       strcpy (memory_trace[memory_trace_size].line, buf);
+                       memory_trace[memory_trace_size].disk_index = disk_index;
+                       memory_trace_size ++;
+
+                       if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                               fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                               break;
+                       }
+                       if ((disk_index%100000)==0)
+                               fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+               } else {
+                       RFS_ASSERT (buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+               }
+#endif
+               disk_index ++;
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+
+}
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index++;
+                       RFS_ASSERT (memory_index < MAX_MEMORY_TRACE_LINES);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index--;
+                       RFS_ASSERT (memory_index >=0);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       p = line+TRACE_MSGID_POS+2;     /* at least one letter for msgid and one letter for space */
+       if (strstr(p, "OK"))
+               return NFS3_OK;
+       if (strstr(p, "lookup 2"))
+               return 0x2;
+       if (strstr(p, "create d"))
+               return 0xd;
+       if (strstr(p, "setattr 1"))
+               return 0x1;
+       if (strstr(p, "lookup d"))
+               return 0xd;
+       if (strstr(p, "read d"))
+               return 0xd;
+       if (strstr(p, "write d"))
+               return 0xd;
+       if (strstr(p, "mkdir d"))
+               return 0xd;
+       printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (0);
+}
+
+inline int find_reply_status_old (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p)
+               printf ("find_reply_trace_fh line %s\n", line);
+       RFS_ASSERT (p);
+       return p+6;
+}
+
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+
+inline int is_play_candidate (int dep_index)
+{
+       int proc = dep_tab[dep_index].proc;
+       int status = dep_tab[dep_index].status;
+       int trace_status = dep_tab[dep_index].trace_status;
+
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       /* for a failed create in trace, trace_replay just ignore many time the trace create fail
+        * due to access control, but trace_play will success because our access control
+        * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+        */
+       if ((proc==CREATE || proc==MKDIR) && (trace_status!=NFS3_OK) && (status!=NFS3ERR_RFS_MISS)) {
+               if (dependency_debug)
+                       printf ("disk[%d] ignore failed create/mkdir in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               failed_create_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_OTHER_FAILED_COMMAND
+       if (((trace_status == NFS3ERR_ACCES) && (proc==READ || proc==WRITE || proc==LOOKUP)) || 
+           ((trace_status == NFS3ERR_PERM) && (proc==SETATTR))                                                                         ){
+               if (dependency_debug)
+                       printf ("disk[%d] ignore other failed command in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               
+               failed_other_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK) ) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+#define TAKE_CARE_CUSTOM_COMMAND
+/* This is actually take care in get_nextop by checking fh_map error when dep_index==min_dep_index */
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+       if ((    ((dep_tab[dep_index].disk_index==262213) || (dep_tab[dep_index].disk_index==214402))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1100.txt")) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_FSSTAT_COMMAND
+       /* the file handle used in this command is not processed properly by pre-processing */
+       if (proc==FSSTAT) {
+               char * trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+               fh_map_t * fh = lookup_fh (trace_fh);
+               if (!fh) {
+                       skipped_fsstat_command_num++;
+                       return FALSE;
+               }
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+static inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+       static int min_wait_fhandle_dep_index = DEP_TAB_SIZE;
+       int proc;
+       int flag;
+
+       //if (dep_index < min_dep_index-1)
+       //      dep_index = min_dep_index-1;
+
+       dep_index = min_dep_index-1;
+       for (i=0; i<max_dep_index-min_dep_index; i++) {
+               dep_index ++;
+               if (dep_index == max_dep_index) {
+                       dep_index = min_dep_index;
+               }
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (dep_index < min_wait_fhandle_dep_index)
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       if (dep_index==min_dep_index) {
+                                               if (!profile_debug) 
+                                                       printf ("fh_path_map error disk[%d] state DEP_FLAG_WAIT_FHANDLE to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                                               fh_path_map_err_num ++;
+                                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                                               continue;
+                                       }
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#define DEPENDENCY_TIMEOUT 5
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       if (tmp.sec >= DEPENDENCY_TIMEOUT) {
+                                               printf("dep_tab[%d].flag %d disk_index %d line %s\n", dep_index,
+                                                       dep_tab[dep_index].flag, dep_tab[dep_index].disk_index,
+                                                       dep_tab[dep_index].line);
+                                       }
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_tab_size;
+                                       for (j=dep_index+1; j<max_dep_index; j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=min_dep_index) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==min_dep_index) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { 
+                                               /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+
+       sfs_gettime (&current); 
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current.sec>timeout.sec) ||
+                               ((current.sec==timeout.sec) && (current.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+                               finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT);
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                               }
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               //printf ("timeout request: biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if (biod_reqp[biod_index].xid == xid) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+       static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                                       22, 19};
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[39], "%x %x", &msgid, &nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+       dep_tab[dep_index].reply_line = find_reply_line (line, dep_tab[dep_index].disk_index);
+       if (dep_tab[dep_index].reply_line == NULL) {
+               //printf ("disk[%d] can not find the reply line, assume trace_status OK\n", dep_tab[dep_index].disk_index);
+               dep_tab[dep_index].trace_status = NFS3ERR_RFS_MISS;
+               missing_reply_num ++;
+       } else 
+               dep_tab[dep_index].trace_status = find_reply_status (dep_tab[dep_index].reply_line);
+}
+
+static void adjust_play_window (int flag, int * poll_timeout)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int old_min = min_dep_index;
+       int old_max = max_dep_index;
+       int i;
+       char * line;
+
+       for (; (dep_tab[min_dep_index].flag == DEP_FLAG_DONE) && (min_dep_index<dep_tab_size); min_dep_index++)
+               ;
+       RFS_ASSERT (min_dep_index <= max_dep_index);
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       while ((max_dep_index<min_dep_index+MAX_PLAY_WINDOW) && (max_dep_index<dep_tab_size))
+       {
+               t.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               t.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+
+               if (adjust_play_window_debug)
+                       printf ("max_window_time sec %d usec %d : max_dep_index %d, t.sec %d t.usec %d\n", max_window_time.sec, max_window_time.usec,  max_dep_index, t.sec, t.usec );
+
+               if ((t.sec>max_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec))
+                       break;
+               
+               max_dep_index++;
+       }
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (max_dep_index == min_dep_index+MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, max_dep_index %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", max_dep_index, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       //RFS_ASSERT (max_dep_index < min_dep_index+MAX_PLAY_WINDOW);
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       max_dep_index = min_dep_index + MAX_PLAY_WINDOW;
+       if (max_dep_index >dep_tab_size)
+               max_dep_index = dep_tab_size;
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout = 0;
+       else if (max_dep_index == dep_tab_size) {
+               *poll_timeout = 1000000;        /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+               if (adjust_play_window_debug)
+                       printf ("dep_tab[max_dep_index %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               max_dep_index, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               max_dep_index, dep_tab[max_dep_index].timestamp.tv_sec, dep_tab[max_dep_index].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+
+               RFS_ASSERT ((tmp.sec < 1000));
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout = 0;
+               } else
+                       *poll_timeout = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+               tmp1.sec = dep_tab[max_dep_index-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[max_dep_index-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout %d \n", flag, old_min, min_dep_index, old_max, max_dep_index, *poll_timeout);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+       RFS_ASSERT (read_data_owe_GB==0);
+       printf("read_data_bytes %d owe %d GB and %d bytes, %d percent, adjusted %d times \n",read_data_total, read_data_owe_GB, read_data_owe, (read_data_owe_GB*1073741824+read_data_owe)/(read_data_total/100), read_data_adjust_times);
+       printf("write_data_bytes %d owe %d GB and %d bytes, %d percent, adjusted %d times \n",write_data_total, write_data_owe_GB, write_data_owe, (write_data_owe_GB*1073741824+write_data_owe)/(write_data_total/100), write_data_adjust_times);
+       printf("poll_timeout_0_num %d poll_timeout_pos_num %d\n", poll_timeout_0_num, poll_timeout_pos_num);
+       printf("failed_create_command_num %d\nfailed_other_command_num %d\nskipped_readlink_command_num %d\nskipped_custom_command_num %d\nfh_path_map_err_num %d\nskipped_fsstat_command_num %d\nmissing_reply_num %d\nrename_rmdir_noent_reply_num %d\nrmdir_not_empty_reply_num %d\nloose_access_control_reply_num %d\nlookup_err_due_to_rename %d\nlookup_eaccess_enoent_mismatch %d\nread_io_err_num %d\nproper_reply_num %d\n", 
+                       failed_create_command_num,
+                       failed_other_command_num,
+                       skipped_readlink_command_num, 
+                       skipped_custom_command_num,
+                       fh_path_map_err_num, 
+                       skipped_fsstat_command_num, 
+                       missing_reply_num, 
+                       rename_rmdir_noent_reply_num, 
+                       rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, 
+                       lookup_err_due_to_rename_num, 
+                       lookup_eaccess_enoent_mismatch_num, 
+                       read_io_err_num, 
+                       proper_reply_num);
+
+    clnt_destroy(NFS_client);
+    biod_term();
+
+//   print_dump(Client_num, Child_num);
+       return;
+       dep_index = 0;
+       printf ("[%4d] %s \tstart %4d:%6d \n",
+               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec);
+       for (i=1; i<dep_tab_size*2; i++) {
+               dep_index = event_order[i];
+               if (dep_index >0) 
+                       printf ("[%4d] %s \tstart %4d:%6d \n",
+                               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec);
+               else {
+                       dep_index = -dep_index;
+                       t=dep_tab[dep_index].stop;
+                       SUBTIME (t, dep_tab[dep_index].start);
+                       printf ("\t\t\t\t\t[%4d] %s stop %4d:%6d\tinterval %4d:%6d %s\n",
+                               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec, t.sec, t.usec, nfs3_strerror(dep_tab[dep_index].status));
+               }       
+       }
+/*
+       
+       for (i=0, j=0; i<dep_tab_size || j<dep_tab_size; ) {
+               if ((i==dep_tab_size) || 
+                       (LARGERTIME(dep_tab[i].start, dep_tab[j].stop) && j<dep_tab_size)) {
+                       t=dep_tab[j].stop;
+                       SUBTIME (t, dep_tab[j].start);
+                       printf ("dep_tab[%d].proc %s                  stop %d:%d interval %d:%d status %s\n",
+                               j, Ops[dep_tab[j].proc].name, dep_tab[j].stop.sec, dep_tab[j].stop.usec, t.sec, t.usec, nfs3_strerror(dep_tab[j].status));
+                       j++;
+               } else {
+                       printf ("dep_tab[%d].proc %s start %d:%d \n",
+                               i, Ops[dep_tab[i].proc].name, dep_tab[i].start.sec, dep_tab[i].start.usec);
+                       i++;
+               }
+       }
+*/
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+extern void init_dep_tab (void)
+{
+       int i;
+       memset (&dep_tab, 0, sizeof(dep_tab));
+#ifdef notdef
+       dep_tab[0].disk_index = 0;
+       dep_tab[1].disk_index = 2;
+       dep_tab[2].disk_index = 3;
+       dep_tab[3].disk_index = 5;
+       dep_tab[4].disk_index = 7;
+       dep_tab[5].disk_index = 9;
+       dep_tab[6].disk_index = 11;
+       dep_tab[7].disk_index = 12;
+       dep_tab[8].disk_index = 15;
+       dep_tab[9].disk_index = 17;
+       dep_tab[10].disk_index = 18;
+       dep_tab[11].disk_index = 20;
+       dep_tab_size = 12;
+       //dep_tab_size = 2;
+#endif
+}
+
+extern void init_dep_tab_old (void)
+{
+       int i;
+
+       Cur_file_ptr = &Export_dir;
+       Cur_uid = Real_uid;
+
+       for (i=0; i<5; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec+i*10;   
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+
+       for (i=5; i<10; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec;        
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+
+       dep_tab[2].init_dep_num = 2;
+       dep_tab[2].cur_dep_num = 2;
+       dep_tab[2].dep_ops[0] = 0;
+       dep_tab[2].dep_ops[1] = 1;
+
+       // printf ("trace_starttime (%d %d)\n", trace_starttime.sec, trace_starttime.usec);
+
+       /*
+       for (i=2; i<4; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i*10;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec;        
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+       */
+
+       dep_tab_size = 10;
+
+       for (i=0; i<dep_tab_size; i++)
+       {
+               printf("dep_tab[%d].timestamp (%d %d)\n", i, dep_tab[i].timestamp.tv_sec, dep_tab[i].timestamp.tv_usec);
+       }
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               //RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               if (memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE)) {
+                       int i;
+                       printf ("fh_map[%d].trace_fh %s trace_fh %s", p->key3, fh_map[p->key3].trace_fh, trace_fh);
+                       for (i=0; i<fh_i; i++) {
+                               int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                               int * p = (int *)fh_map[i].trace_fh;
+                               printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                               printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, fh_map[i].trace_fh, fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+                       }
+#endif
+                       RFS_ASSERT (0);
+               }
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               /* It's possible that in fh-path-map, many trace_fh are corresponding to one path
+                * some of it may be the result of lookup after symlink, which is not handled
+                * properly as new created objects 
+                */
+#ifdef TAKE_CARE_SYMBOLIC_LINK
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+#endif
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       strncpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       //show_fhandle(play_fh);
+               } else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+inline fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i[%d] trace_fh %s path %s play_fh:\n", p->key3, fh_map[p->key3].trace_fh, fh_map[p->key3].path);
+                       //show_fhandle(&fh_map[p->key3].play_fh);
+               }
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+void lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       RFS_ASSERT (reply.status == NFS3_OK);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7)) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);         
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline void finish_request (int biod_index, int dep_index, int status)
+{
+       /* the ending operation, same as when a request time out */
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       dep_tab[dep_index].status = status;
+       event_order[event_order_index++] = -dep_index;
+       biod_reqp[biod_index].in_use = FALSE;
+       dep_tab[dep_index].flag = DEP_FLAG_DONE;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+       num_out_reqs --;
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+int poll_timeout = 0;          /* timeout in usecs */
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+       if ((dep_index%(10000))==0) {
+#ifndef TIME_PLAY
+               fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs);
+#else
+               fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+#ifdef SPEED_UP
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+#endif
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+       call_timeout.sec = 2; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#else
+
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    if (reqp->xid != 0) {
+        reqp->timeout = reqp->start;
+        ADDTIME (reqp->timeout, call_timeout);
+        num_out_reqs++;
+        dep_tab[dep_index].flag = DEP_FLAG_SENT;
+               event_order[event_order_index++] = dep_index;
+    } else
+               RFS_ASSERT (0);
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+}
+
+inline void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_status)
+{
+       if (((status!=trace_status)) && (trace_status!=NFS3ERR_RFS_MISS)) {
+               if (!profile_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_status == 0)) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+#endif
+#ifndef TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+               /* if the looked return EACCESS in the trace, means the object still exists
+                * should have initialized, right not don't initialize it, hence play status 
+                * could be ENOENT
+                */
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3ERR_ACCES)) {
+                       lookup_eaccess_enoent_mismatch_num ++;
+#endif
+#ifdef TOLERANT_READ_IO_ERR
+               } else if ((proc==READ) && (status==NFS3ERR_IO) && (trace_status==NFS3_OK)) {
+                       read_io_err_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=min_dep_index; i<max_dep_index; i++) 
+                               printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       RFS_ASSERT (0);
+               }
+       } else 
+               proper_reply_num ++;
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+inline int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_status;
+       char * errmsg;
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+
+       if (busy_flag == BUSY) {
+               poll_timeout = 0;
+               poll_timeout_0_num ++;
+       } else {
+               poll_timeout = 10000;   /* 10000 or 2000 is a better number in non-debugging state */
+               poll_timeout_pos_num ++;
+       }
+
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = dep_tab[dep_index].reply_line;
+       trace_status = dep_tab[dep_index].trace_status;
+
+       /* print the result, trace play progress indicator */
+       if (rfs_debug || (      !profile_debug && ((dep_index %10000)==0)       ) )
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status);
+       
+       /* get statistics */
+       if (status == trace_status) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       
+       //start_profile (&add_create_object_profile);
+/*
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==MKNOD)) {
+#else
+#endif
+*/
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+               RFS_ASSERT (reply_line);
+               if (status!=NFS3_OK) {
+                       RFS_ASSERT (proc==SYMLINK);
+               } else {
+                       if (proc!=SYMLINK || line[TRACE_VERSION_POS]!='2')
+                               add_new_file_system_object(proc, dep_index, line, reply_line);
+               }
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, max_dep_index> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+
+       int count = 0;
+       min_dep_index = 0;
+       max_dep_index = 0;
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while ((min_dep_index<dep_tab_size) || (num_out_reqs>0)) {
+
+               if (busy_flag == IDLE) {
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               //adjust_play_window (flag, &poll_timeout);
+               //adjust_play_window (flag+(max_dep_index-min_dep_index), &poll_timeout);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1)
+                       busy_flag = BUSY;
+               end_profile (&execute_next_request_profile);
+
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+#endif
+               end_profile (&receive_next_reply_profile);
+       }
+       end_profile (&total_profile);
+
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       //print_profile ("check_timeout", &check_timeout_profile);
+       //printf("\n");
+       //print_profile ("adjust_play_window", &adjust_play_window_profile);
+       //printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument", &prepare_argument_profile);
+       print_profile ("biod_clnt_call", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply", &decode_reply_profile);
+       print_profile ("check_reply", &check_reply_profile);
+       //print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("min_dep_index %d dep_tab_size %d num_out_reqs %d\n", min_dep_index, dep_tab_size, num_out_reqs);
+}
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_chd.c.old.2 b/TBBT/trace_play/sfs_c_chd.c.old.2
new file mode 100644 (file)
index 0000000..a8c71f7
--- /dev/null
@@ -0,0 +1,2294 @@
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static void read_trace(char * trace_file);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+static void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+static void adjust_play_window (int flag, int * poll_timeout);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern fh_map_t * lookup_fh (char * trace_fh );
+static inline void finish_request (int biod_index, int dep_index, int status);
+static void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+void print_usage()
+{
+       printf("sfs3 hostname:mount_dir trace_file fh_map_file\n");
+       exit;
+}
+
+void read_dep_tab()
+{
+#ifdef NO_DEPENDENCY_TABLE
+       int i;
+       char * line;
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       int req_num_with_new_fh = 0;
+       int     req_num_with_discard_fh = 0;
+       int req_num_with_init_fh =0;
+
+       for (i=0; i<memory_trace_size; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='C') {
+                       trace_fh = strstr (line, "fh");
+                       RFS_ASSERT (trace_fh);
+                       trace_fh += 3;
+                       fh_map_entry = lookup_fh (trace_fh);
+                       if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+                               req_num_with_discard_fh ++;
+                               continue;
+                       }
+                       if (fh_map_entry)
+                               req_num_with_init_fh ++;
+                       else
+                               req_num_with_new_fh ++;
+
+                       dep_tab[dep_tab_size].disk_index = memory_trace[i].disk_index;
+                       dep_tab[dep_tab_size].line = memory_trace[i].line;
+                       if ((dep_tab_size%100000)==0)
+                               printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_size, dep_tab[dep_tab_size].disk_index, i, memory_trace[i].disk_index);
+                       dep_tab_size ++;
+               }
+       }
+#else
+       RFS_ASSERT (0);
+#endif
+       printf ("read_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+}
+
+void init_profile()
+{
+       memset (&total_profile, 0, sizeof(total_profile));
+
+       memset (&execute_next_request_profile, 0, sizeof(execute_next_request_profile));
+       memset (&valid_get_nextop_profile, 0, sizeof(valid_get_nextop_profile));
+       memset (&invalid_get_nextop_profile, 0, sizeof(invalid_get_nextop_profile));
+       memset (&prepare_argument_profile, 0, sizeof(prepare_argument_profile));
+       memset (&biod_clnt_call_profile, 0, sizeof(biod_clnt_call_profile));
+
+       memset (&receive_next_reply_profile, 0, sizeof(receive_next_reply_profile));
+       memset (&valid_poll_and_get_reply_profile, 0, sizeof(valid_poll_and_get_reply_profile));
+       memset (&invalid_poll_and_get_reply_profile, 0, sizeof(invalid_poll_and_get_reply_profile));
+       memset (&decode_reply_profile, 0, sizeof(decode_reply_profile));
+       memset (&check_reply_profile, 0, sizeof(check_reply_profile));
+       memset (&add_create_object_profile, 0, sizeof(add_create_object_profile));
+
+       memset (&check_timeout_profile, 0, sizeof(check_timeout_profile));
+       memset (&adjust_play_window_profile, 0, sizeof(adjust_play_window_profile));
+}
+
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       char tracefile[256];
+       int i;
+       int memory_trace_size;
+
+       if (argc==2 && !strcmp(argv[1],"-help")) {
+               print_usage();
+               exit(0);
+       }
+
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_file_system ();
+
+       init_signal();
+       //init_play (argv[1]);
+       init_play ("capella:/p5/RFSFS");
+       init_profile();
+       init_fh_map();
+       //read_fh_map (argv[3]);
+       read_fh_map ("fh-path-map");
+       init_dep_tab();                 /* and  dep_tab_size */
+       //read_trace (argv[2]);
+       read_trace ("anon-lair62-011130-1100.txt");
+       stage = READ_DEP_TAB_STAGE;
+       read_dep_tab();
+
+       for (i=0; i<dep_tab_size; i++) {
+               RFS_ASSERT (dep_tab[i].flag == DEP_FLAG_FREE) 
+               init_dep_tab_entry (i);
+       }
+       stage = TRACE_PLAY_STAGE;
+       init_time_offset();
+       trace_play ();
+       print_result();
+       printf("ffff\n");
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+       
+
+}
+
+void read_trace (char * tracefile)
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(tracefile, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, 1024, fp)) {
+               //printf ("buf: %s buf[36] %c\n", buf, buf[36]);
+               //if (buf[36]=='C' || strstr(buf, "create") || strstr(buf, "lookup")) {
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]=='C' || strstr(buf, "create") || 
+                       strstr(buf, "mkdir") || strstr(buf, "symlink") || strstr(buf, "mknod") || strstr(buf, "lookup")) {
+#endif
+                       if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                               printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+                       RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+                       /* store the request to memory */
+                       strcpy (memory_trace[memory_trace_size].line, buf);
+                       memory_trace[memory_trace_size].disk_index = disk_index;
+                       memory_trace_size ++;
+
+                       if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                               printf ("memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                               break;
+                       }
+                       if ((disk_index%100000)==0)
+                               fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+               } else {
+                       RFS_ASSERT (buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+               }
+#endif
+               disk_index ++;
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+
+}
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index++;
+                       RFS_ASSERT (memory_index < MAX_MEMORY_TRACE_LINES);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index--;
+                       RFS_ASSERT (memory_index >=0);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p)
+               printf ("find_reply_trace_fh line %s\n", line);
+       RFS_ASSERT (p);
+       return p+6;
+}
+
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+
+inline int is_play_candidate (int dep_index)
+{
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       int trace_reply_status;
+       char * reply_line;
+       if ((dep_tab[dep_index].proc==CREATE)) {
+               /* for a failed create in trace, trace_replay just ignore */
+               reply_line = find_reply_line (dep_tab[dep_index].line, dep_tab[dep_index].disk_index);
+               if (reply_line == NULL) {
+                       if (dependency_debug)
+                               printf ("disk[%d] can not find the reply line, assume trace_reply_status OK\n", dep_tab[dep_index].disk_index);
+                       trace_reply_status = NFS3_OK;
+               } else 
+                       trace_reply_status = find_reply_status (reply_line);
+               /* many time the trace create fail due to access control, but trace_play will success because our access control
+                * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+                */
+               if ((dep_tab[dep_index].proc == CREATE) && (trace_reply_status!=NFS3_OK)) {
+                       if (dependency_debug)
+                               printf ("disk[%d] ignore failed create in trace, trace_reply_status %d line %s", dep_tab[dep_index].disk_index, trace_reply_status, dep_tab[dep_index].line);
+                       failed_create_command_num ++;
+                       return FALSE;
+               }
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK)) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+       if ((dep_tab[dep_index].disk_index==262213 ||
+                dep_tab[dep_index].disk_index==214402          )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+       static int min_wait_fhandle_dep_index = DEP_TAB_SIZE;
+       int proc;
+       int flag;
+
+       //if (dep_index < min_dep_index-1)
+       //      dep_index = min_dep_index-1;
+
+       dep_index = min_dep_index-1;
+       for (i=0; i<max_dep_index-min_dep_index; i++) {
+               dep_index ++;
+               if (dep_index == max_dep_index) {
+                       dep_index = min_dep_index;
+               }
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (dep_index < min_wait_fhandle_dep_index)
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < 20 + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       RFS_ASSERT (tmp.sec < 20 );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_tab_size;
+                                       for (j=dep_index+1; j<max_dep_index; j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=min_dep_index) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==min_dep_index) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+
+       sfs_gettime (&current); 
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current.sec>timeout.sec) ||
+                               ((current.sec==timeout.sec) && (current.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+                               finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT);
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                               }
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               //printf ("timeout request: biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if (biod_reqp[biod_index].xid == xid) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+       static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                                       22, 19};
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[39], "%x %x", &msgid, &nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+}
+
+/* initialize status, reply status, reply lines in one shot is probably better ????????????????
+
+static void adjust_play_window (int flag, int * poll_timeout)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int old_min = min_dep_index;
+       int old_max = max_dep_index;
+       int i;
+       char * line;
+
+       for (; (dep_tab[min_dep_index].flag == DEP_FLAG_DONE) && (min_dep_index<dep_tab_size); min_dep_index++)
+               ;
+       RFS_ASSERT (min_dep_index <= max_dep_index);
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       while ((max_dep_index<min_dep_index+MAX_PLAY_WINDOW) && (max_dep_index<dep_tab_size))
+       {
+               t.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               t.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+
+               if (adjust_play_window_debug)
+                       printf ("max_window_time sec %d usec %d : max_dep_index %d, t.sec %d t.usec %d\n", max_window_time.sec, max_window_time.usec,  max_dep_index, t.sec, t.usec );
+
+               if ((t.sec>max_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec))
+                       break;
+               
+               max_dep_index++;
+       }
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (max_dep_index == min_dep_index+MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, max_dep_index %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", max_dep_index, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       //RFS_ASSERT (max_dep_index < min_dep_index+MAX_PLAY_WINDOW);
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       max_dep_index = min_dep_index + MAX_PLAY_WINDOW;
+       if (max_dep_index >dep_tab_size)
+               max_dep_index = dep_tab_size;
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout = 0;
+       else if (max_dep_index == dep_tab_size) {
+               *poll_timeout = 1000000;        /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+               if (adjust_play_window_debug)
+                       printf ("dep_tab[max_dep_index %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               max_dep_index, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               max_dep_index, dep_tab[max_dep_index].timestamp.tv_sec, dep_tab[max_dep_index].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+
+               RFS_ASSERT ((tmp.sec < 1000));
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout = 0;
+               } else
+                       *poll_timeout = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec;
+               tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec;
+               tmp1.sec = dep_tab[max_dep_index-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[max_dep_index-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout %d \n", flag, old_min, min_dep_index, old_max, max_dep_index, *poll_timeout);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+       printf("read_data_bytes %d owe %d GB and %d bytes, adjusted %d times \n",read_data_total, read_data_owe_GB, read_data_owe, read_data_adjust_times);
+       printf("write_data_bytes %d owe %d GB and %d bytes, adjusted %d times \n",write_data_total, write_data_owe_GB, write_data_owe, write_data_adjust_times);
+       printf("failed_create_command_num %d skipped_readlink_command_num %d skipped_custom_command_num %d\n missing_reply_num %d rename_rmdir_noent_reply_num %d rmdir_not_empty_reply_num %d\n loose_access_control_reply_num %d, proper_reply_num %d, lookup_err_due_to_rename %d\n", 
+                       failed_create_command_num, skipped_readlink_command_num, skipped_custom_command_num,
+                       missing_reply_num, rename_rmdir_noent_reply_num, rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, lookup_err_due_to_rename_num, proper_reply_num );
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+    clnt_destroy(NFS_client);
+    biod_term();
+
+//   print_dump(Client_num, Child_num);
+       return;
+       dep_index = 0;
+       printf ("[%4d] %s \tstart %4d:%6d \n",
+               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec);
+       for (i=1; i<dep_tab_size*2; i++) {
+               dep_index = event_order[i];
+               if (dep_index >0) 
+                       printf ("[%4d] %s \tstart %4d:%6d \n",
+                               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec);
+               else {
+                       dep_index = -dep_index;
+                       t=dep_tab[dep_index].stop;
+                       SUBTIME (t, dep_tab[dep_index].start);
+                       printf ("\t\t\t\t\t[%4d] %s stop %4d:%6d\tinterval %4d:%6d %s\n",
+                               dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec, t.sec, t.usec, nfs3_strerror(dep_tab[dep_index].status));
+               }       
+       }
+/*
+       
+       for (i=0, j=0; i<dep_tab_size || j<dep_tab_size; ) {
+               if ((i==dep_tab_size) || 
+                       (LARGERTIME(dep_tab[i].start, dep_tab[j].stop) && j<dep_tab_size)) {
+                       t=dep_tab[j].stop;
+                       SUBTIME (t, dep_tab[j].start);
+                       printf ("dep_tab[%d].proc %s                  stop %d:%d interval %d:%d status %s\n",
+                               j, Ops[dep_tab[j].proc].name, dep_tab[j].stop.sec, dep_tab[j].stop.usec, t.sec, t.usec, nfs3_strerror(dep_tab[j].status));
+                       j++;
+               } else {
+                       printf ("dep_tab[%d].proc %s start %d:%d \n",
+                               i, Ops[dep_tab[i].proc].name, dep_tab[i].start.sec, dep_tab[i].start.usec);
+                       i++;
+               }
+       }
+*/
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+extern void init_dep_tab (void)
+{
+       int i;
+       memset (&dep_tab, 0, sizeof(dep_tab));
+#ifdef notdef
+       dep_tab[0].disk_index = 0;
+       dep_tab[1].disk_index = 2;
+       dep_tab[2].disk_index = 3;
+       dep_tab[3].disk_index = 5;
+       dep_tab[4].disk_index = 7;
+       dep_tab[5].disk_index = 9;
+       dep_tab[6].disk_index = 11;
+       dep_tab[7].disk_index = 12;
+       dep_tab[8].disk_index = 15;
+       dep_tab[9].disk_index = 17;
+       dep_tab[10].disk_index = 18;
+       dep_tab[11].disk_index = 20;
+       dep_tab_size = 12;
+       //dep_tab_size = 2;
+#endif
+}
+
+extern void init_dep_tab_old (void)
+{
+       int i;
+
+       Cur_file_ptr = &Export_dir;
+       Cur_uid = Real_uid;
+
+       for (i=0; i<5; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec+i*10;   
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+
+       for (i=5; i<10; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec;        
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+
+       dep_tab[2].init_dep_num = 2;
+       dep_tab[2].cur_dep_num = 2;
+       dep_tab[2].dep_ops[0] = 0;
+       dep_tab[2].dep_ops[1] = 1;
+
+       // printf ("trace_starttime (%d %d)\n", trace_starttime.sec, trace_starttime.usec);
+
+       /*
+       for (i=2; i<4; i++) {
+               dep_tab[i].flag = DEP_FLAG_INIT;
+               dep_tab[i].proc = CREATE;
+               dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i*10;
+           dep_tab[i].timestamp.tv_usec = trace_starttime.usec;        
+               dep_tab[i].init_dep_num = 0;
+               dep_tab[i].cur_dep_num = 0;
+       }
+       */
+
+       dep_tab_size = 10;
+
+       for (i=0; i<dep_tab_size; i++)
+       {
+               printf("dep_tab[%d].timestamp (%d %d)\n", i, dep_tab[i].timestamp.tv_sec, dep_tab[i].timestamp.tv_usec);
+       }
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       memcpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE)
+                       show_fhandle(play_fh);
+               else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i %d path %s play_fh:", p->key3, fh_map[p->key3].path);
+                       show_fhandle(&fh_map[p->key3].play_fh);
+               }
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+void lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       RFS_ASSERT (reply.status == NFS3_OK);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7)) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);         
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline void finish_request (int biod_index, int dep_index, int status)
+{
+       /* the ending operation, same as when a request time out */
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       dep_tab[dep_index].status = status;
+       event_order[event_order_index++] = -dep_index;
+       biod_reqp[biod_index].in_use = FALSE;
+       dep_tab[dep_index].flag = DEP_FLAG_DONE;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+       num_out_reqs --;
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+int poll_timeout = 0;          /* timeout in usecs */
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+#define NFS3_REPLY_MISS -1
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+       if ((dep_index%(10000))==0) {
+#ifndef TIME_PLAY
+               fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs);
+#else
+               fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+#ifdef SPEED_UP
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+#endif
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+       call_timeout.sec = 4; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#else
+
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    if (reqp->xid != 0) {
+        reqp->timeout = reqp->start;
+        ADDTIME (reqp->timeout, call_timeout);
+        num_out_reqs++;
+        dep_tab[dep_index].flag = DEP_FLAG_SENT;
+               event_order[event_order_index++] = dep_index;
+    } else
+               RFS_ASSERT (0);
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+}
+
+void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_reply_status)
+{
+       if (((status!=trace_reply_status)) && (trace_reply_status!=NFS3_REPLY_MISS)) {
+               if (rfs_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_reply_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_reply_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_reply_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       RFS_ASSERT (1);
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_reply_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_reply_status == 0)) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_reply_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_reply_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=min_dep_index; i<max_dep_index; i++) 
+                               printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       RFS_ASSERT (0);
+               }
+       } else 
+               proper_reply_num ++;
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_reply_status;
+       char * errmsg;
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+/*
+       if (busy_flag == IDLE)
+               poll_timeout = 0;
+       else 
+               poll_timeout = 10000;
+*/
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = find_reply_line (line, dep_tab[dep_index].disk_index);
+       if (reply_line == NULL) {
+               //printf ("disk[%d] can not find the reply line, assume trace_reply_status OK\n", dep_tab[dep_index].disk_index);
+               trace_reply_status = NFS3_REPLY_MISS;
+               missing_reply_num ++;
+       } else 
+               trace_reply_status = find_reply_status (reply_line);
+
+       /* print the result, trace play progress indicator */
+       if ((dep_index %10000)==0 || rfs_debug)
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_reply_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_reply_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_reply_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status);
+       
+       /* get statistics */
+       if (status == trace_reply_status) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       
+       //start_profile (&add_create_object_profile);
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if (trace_reply_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==MKNOD)) {
+#else
+       if (trace_reply_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+#endif
+               RFS_ASSERT (status == NFS_OK);
+               RFS_ASSERT (reply_line);
+               add_new_file_system_object(proc, dep_index, line, reply_line);
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, max_dep_index> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+
+       int count = 0;
+       min_dep_index = 0;
+       max_dep_index = 0;
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while ((min_dep_index<dep_tab_size) || (num_out_reqs>0)) {
+
+               if (busy_flag == IDLE) {
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               //adjust_play_window (flag, &poll_timeout);
+               //adjust_play_window (flag+(max_dep_index-min_dep_index), &poll_timeout);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1)
+                       busy_flag = BUSY;
+               end_profile (&execute_next_request_profile);
+
+               start_profile (&receive_next_reply_profile);
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+               end_profile (&receive_next_reply_profile);
+       }
+       end_profile (&total_profile);
+
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       print_profile ("check_timeout", &check_timeout_profile);
+       printf("\n");
+       print_profile ("adjust_play_window", &adjust_play_window_profile);
+       printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument", &prepare_argument_profile);
+       print_profile ("biod_clnt_call", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply", &decode_reply_profile);
+       print_profile ("check_reply", &check_reply_profile);
+       print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("min_dep_index %d dep_tab_size %d num_out_reqs %d\n", min_dep_index, dep_tab_size, num_out_reqs);
+}
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_chd.c.org b/TBBT/trace_play/sfs_c_chd.c.org
new file mode 100644 (file)
index 0000000..27a122c
--- /dev/null
@@ -0,0 +1,2866 @@
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+
+/* forward definitions for local functions */
+static void check_call_rate(void);
+static void init_targets(void);
+static int init_rpc(void);
+static void init_testdir(void);
+static int do_op(void);
+static int op(int);
+static void init_dirlayout(void);
+
+
+/*
+ * -------------------  File Set Size Control -------------------------
+ */
+static uint_t Setattr_borrowed = 0;    /* setattr op used for file truncate */
+static uint_t Create_borrowed = 0;             /* create op used for file truncate */
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static float Child_call_load;  /* per child call/sec rate */
+static float Child_req_load;   /* per child req/sec rate */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+static int Measurement_in_progress = 0;
+
+static sfs_work_set_type Dir_working_set;
+static sfs_work_set_type Io_working_set;
+static sfs_work_set_type Non_io_working_set;
+static sfs_work_set_type Symlink_working_set;
+
+static uint_t Files_created = 0;         /* unique integer part of file names */
+static char io_buf[BUFSIZ];
+int generations = 
+       (_WORKING_SET_AT_25_OPS_PER_SEC/_GROUP_DIVISOR) * _MIN_GROUPS;
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+
+/*
+ * Child number 'child_num'.  Initialize internal data structure and
+ * the test directory,  then notify parent (through log file) that we
+ * are ready to start generating 'load' calls per second into the current
+ * working directory, or optionally, into the directories specified by
+ * 'argc' and 'argv'.  Wait for the start signal, and then generate load
+ * until we complete all our goal for calls or until the run time expires,
+ * depending on the 'Timed_run' flag.  The run time expires when the parent
+ * sends the stop signal.
+ */
+void
+child(
+    int                child_num,
+    int                children,
+    float      load,
+    int        argc,
+    char       *argv[])
+{
+    char       namebuf[NFS_MAXNAMLEN]; /* unique name for this program */
+    char       *nameptr;
+    int                i;                      /* general use */
+    int                op_count;               /* ops completed during each request */
+    uint_t     rand_sleep_msec;        /* random sleep msec between calls */
+    uint_t     current_msec;           /* current test time in msecs */
+    double     previous_pcnt;
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+    char *     mount_point;            /* Mount point for remote FS */
+    int                Saveerrno;
+    int                mnt_argc;
+
+    struct ladtime     elapsed_time;   /* Current_time - Start_time */
+    sfs_results_report_type    report; /* final results log */
+
+    (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    /* Change my name for error logging */
+    if ((nameptr = strrchr(sfs_Myname, '/')) != NULL)
+       sfs_Myname = ++nameptr;
+    (void) sprintf(namebuf, "%s%d", sfs_Myname, child_num);
+    sfs_Myname = namebuf;
+    Child_call_load = load;
+    Current_test_phase = Mount_phase;
+
+    /* Seed the random number generator based on my child number */
+
+    /*
+     * Note: If random seeds are allocated by the prime client
+     * then this code must change.
+     */
+    sfs_srandom((int)(load + Child_num + 1));
+
+    /* Setup user and group information */
+    Cur_uid = Real_uid;
+
+    /*
+     * Initialize call and request targets.
+     * Calls are the Over-The-Wire (OTW) operations that occur due to
+     * each request.  A request may cause one or more calls.
+     * Initialize the child file info and mount the remote test directory.
+     * Set up the rpc and biod structures.
+     */
+    init_targets();
+    init_fileinfo();
+    init_dirlayout();
+
+    /*
+     * Mount points list:
+     *   If the mount point list is equal to the number of procs (P), the
+     *   mount point for child M is the M'th entry in the list.
+     *   If the mount point list is greater than the number of procs (P), the
+     *   mount point for client N child M is ((N - 1) * P) + M
+     */
+    if (argc == children)
+       mnt_argc = Child_num;
+    else
+       mnt_argc = (Client_num - 1) * children + Child_num;
+
+    if (mnt_argc >= argc) {
+       (void) fprintf(stderr,
+"%s: Invalid mount point list: required %d only specified %d mount points\n",
+                       sfs_Myname, mnt_argc + 1, argc);
+       (void) generic_kill(0, SIGINT);
+       exit(181);
+    }
+
+    mount_point = argv[mnt_argc];
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+       exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+       (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(146);
+    }
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(Child_num, mount_point, mount_client_ptr);
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+    /*
+     * Tell parent I'm ready to initialize my test directory,
+     * wait for the go ahead signal.
+     */
+    if (write(Log_fd, "x", 1) != 1) {
+       (void) fprintf(stderr, "%s: can't write to synchronization file %s",
+                       sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(147);
+    }
+    (void) pause();
+
+    if (DEBUG_CHILD_GENERAL) {
+       if (Timed_run) {
+           if (Prime_client) {
+               (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d seconds\n",
+                   Child_num, Child_call_load, Child_req_load,
+                   Runtime - MULTICLIENT_OFFSET);
+           }
+           else {
+           (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d seconds\n",
+                   Child_num, Child_call_load, Child_req_load, Runtime);
+           }
+       } else {
+           (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d calls\n",
+                   Child_num, Child_call_load, Child_req_load,
+                   Ops[TOTAL].target_calls);
+       }
+       (void) fflush(stderr);
+    }
+
+    /* Initialize the test directory */
+    Current_test_phase = Populate_phase;
+    init_testdir();
+
+    /*
+     * activate the biod behaviour if desired
+     */
+    if (Biod_max_outstanding_reads > 0 || Biod_max_outstanding_writes > 0) {
+       biod_turn_on();
+    }
+
+    /*
+     * Tell parent I'm ready to start test, wait for the go ahead signal.
+     */
+    if (write(Log_fd, "x", 1) != 1) {
+       (void) fprintf(stderr, "%s: can't write to synchronization file %s\n",
+                       sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(148);
+    }
+    (void) pause();
+
+    if (DEBUG_CHILD_GENERAL) {
+       if (Timed_run) {
+           if (Prime_client) {
+               (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d seconds\n",
+                   Child_num, Child_call_load, Child_req_load,
+                   Runtime - MULTICLIENT_OFFSET);
+           }
+           else {
+           (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d seconds\n",
+                   Child_num, Child_call_load, Child_req_load, Runtime);
+           }
+       } else {
+           (void) fprintf(stderr,
+       "Child %d loading at %3.2f calls/sec (%3.2f reqs/sec) for %d calls\n",
+                   Child_num, Child_call_load, Child_req_load,
+                   Ops[TOTAL].target_calls);
+       }
+       (void) fflush(stderr);
+    }
+
+
+    /* Start the warmup phase; initialize operation counters */
+    Current_test_phase = Warmup_phase;
+    init_counters();
+    Measurement_in_progress = 0;
+
+    /*
+     * Compute the average sleep time per call.
+     * Start off with the assumption that we can sleep half the time.
+     * Note: using msec-per-call to adjust sleeping time
+     * limits benchmark load rates to less than 1000 calls-per-sec-per-child.
+     */
+    Target_sleep_mspc = (int) (((1000.0 / Child_call_load) / 2.0) + .5);
+
+    /*
+     * Occasionally, check to see if ops are being generating at the
+     * correct rate.  During the warmup phase, checks are made every 2 seconds.
+     * Hopefully, this will allow the test to reach steady state before the
+     * warmup phase ends.  During the timed test run, checks are made every
+     * 10 seconds.  The switch is made when we receive the start signal.
+     */
+    Msec_per_period = DEFAULT_WARM_RATE_CHECK * 1000;
+
+    /* Loop generating load */
+    while ((Timed_run && Runtime) ||
+          (!Timed_run &&
+           (Ops[TOTAL].results.good_calls < Ops[TOTAL].target_calls))) {
+
+       if (start_run_phase) {
+           init_counters();
+           Measurement_in_progress = 1;
+           /*
+            * Progress is checked every 10 seconds during the test run.
+            */  
+           Msec_per_period = DEFAULT_RUN_RATE_CHECK * 1000;
+
+           start_run_phase = 0;
+       }
+
+       /* Do an NFS operation, unless we need to sleep for the whole period. */
+       if (Target_sleep_mspc < Msec_per_period)
+           op_count = do_op();
+       else
+           op_count = 0;
+
+       /* if the call was successful, add op_count to the period total. */
+       if (op_count > 0) {
+           Calls_this_period += op_count;
+           Reqs_this_period++;
+       }
+
+       /*
+        * If the call was successful,
+        * or we need to sleep for the whole period,
+        * sleep for a while before doing the next op.
+        */
+       if ((op_count > 0) || (Target_sleep_mspc >= Msec_per_period)) {
+           /*
+            * Sleep for the whole period or
+            * for a random (positive) time period in the range
+            * (Target_sleep_mspc +- 1/2(Target_sleep_mspc)).
+            */
+           if (Target_sleep_mspc >= Msec_per_period)
+               rand_sleep_msec =  Msec_per_period;
+           else if (Target_sleep_mspc >= 1)
+               rand_sleep_msec = (Target_sleep_mspc >> 1)
+                                 + (sfs_random() % Target_sleep_mspc);
+           else
+               rand_sleep_msec = 0;
+
+           if (rand_sleep_msec != 0) {
+               if (DEBUG_CHILD_TIMING) {
+                   (void) fprintf(stderr, "Child %d sleep for %d msec\n",
+                                       Child_num, rand_sleep_msec);
+                   (void) fflush(stderr);
+               }
+               Sleep_msec_this_period += msec_sleep(rand_sleep_msec);
+           }
+       }
+
+       /*
+        * See if it's time to check our progress.
+        * If an operation was just performed, then Cur_time was updated
+        * in the op routine; otherwise we need to get Cur_time.
+        */
+       if (op_count <= 0) {
+           sfs_gettime(&Cur_time);
+       }
+
+       current_msec = (Cur_time.sec * 1000) + (Cur_time.usec / 1000);
+       if (DEBUG_CHILD_XPOINT) {
+               (void) fprintf(stderr, "cur=%d prev=%d per=%d\n",
+                       current_msec, Previous_chkpnt_msec, Msec_per_period);
+       }
+
+       if ((current_msec - Previous_chkpnt_msec) > Msec_per_period) {
+           check_call_rate();
+       }
+
+    } /* end while more calls to make */
+
+    /*
+     * We are done generating our part of the load.
+     * Store total time in last slot of counts array.
+     *
+     * The last slot has the wall clock time of all the load generation.
+     * Individual slots have the wall clock time spent just for the op
+     * gen routine.
+     */
+    sfs_gettime(&Cur_time);
+    Measurement_in_progress = 0;
+    elapsed_time.sec = Cur_time.sec;
+    elapsed_time.usec = Cur_time.usec;
+    SUBTIME(elapsed_time, Starttime);
+
+    Ops[TOTAL].results.time.sec = elapsed_time.sec;
+    Ops[TOTAL].results.time.usec = elapsed_time.usec;
+
+    if (DEBUG_CHILD_FILES) {
+       (void) fprintf(stderr,
+                   "%s: max fss %d KB  min fss %d KB\n",
+                       sfs_Myname, Most_fss_bytes, Least_fss_bytes);
+       (void) fflush(stderr);
+    }
+
+    if (DEBUG_CHILD_FILES) {
+       (void) fprintf(stderr, "Child %d Files:\n", Child_num);
+       for (i = 0; i < Num_io_files; i++)
+           (void) fprintf(stderr, "Io[%d] use %d xfer %d\n",
+                               i, Io_files[i].use_cnt, Io_files[i].xfer_cnt);
+       for (i = 0; i < Num_non_io_files; i++)
+           (void) fprintf(stderr, "Non_io[%d] use %d xfer %d\n",
+                               i, Non_io_files[i].use_cnt,
+                               Non_io_files[i].xfer_cnt);
+       for (i = 0; i < Num_dir_files; i++)
+           (void) fprintf(stderr, "Dir[%d] use %d xfer %d\n",
+                               i, Dirs[i].use_cnt, Dirs[i].xfer_cnt);
+       for (i = 0; i < Num_symlink_files; i++)
+           (void) fprintf(stderr, "Sym[%d] use %d xfer %d\n",
+                               i, Symlinks[i].use_cnt, Symlinks[i].xfer_cnt);
+       (void) fflush(stderr);
+    }
+
+    if (DEBUG_CHILD_SETUP) {
+       int j, group_size, offset, index, tot;
+       for (i = 0; i < Io_working_set.access_group_cnt; i++) {
+           group_size = Io_working_set.access_group_size;
+           if (i < (Num_working_io_files -
+                    ((Num_working_io_files / Io_working_set.access_group_cnt)
+                     * Io_working_set.access_group_cnt)))
+               group_size += 1;
+           tot = 0;
+           for (j = 0; j < group_size; j++) {
+               offset = i + (j * Io_working_set.access_group_cnt);
+               index = Io_working_set.entries[offset].index;
+               tot += Io_files[index].use_cnt;
+               (void) fprintf(stderr, "Working[%d] use %d xfer %d\n",
+                               offset, Io_files[index].use_cnt,
+                               Io_files[index].xfer_cnt);
+           }
+           (void) fprintf(stderr, "Group %d total use %d\n", i, tot);
+       }
+       (void) fflush(stderr);
+    }
+
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "Child %d Ops:\n", Child_num);
+
+       previous_pcnt = 0.0;
+       (void) fprintf(stderr,
+    "             calls                             reqs\n");
+       (void) fprintf(stderr,
+    "             trgt actl  trgt actl  bad  no     trgt actl   trgt   actl\n");
+       (void) fprintf(stderr,
+    "     name    mix  mix   cnt   cnt  cnt  cnt     mix  mix    cnt    cnt\n");
+
+       for (i = 0; i < NOPS + 1; i++) {
+           (void) fprintf(stderr,
+                   "%11s %4d %4.1f %5d %5d %4d %3d    %4.1f %4.1f %6d %6d\n",
+                   Ops[i].name, Ops[i].mix_pcnt,
+                   (float) (100 * Ops[i].results.good_calls)
+                       / (float) Ops[TOTAL].results.good_calls,
+                   Ops[i].target_calls, Ops[i].results.good_calls,
+                   Ops[i].results.bad_calls, Ops[i].no_calls,
+                   Ops[i].req_pcnt - previous_pcnt,
+                   (float) (100 * Ops[i].req_cnt) / (float) Ops[TOTAL].req_cnt,
+                   Ops[i].target_reqs, Ops[i].req_cnt);
+           previous_pcnt = Ops[i].req_pcnt;
+       }
+       (void) fflush(stderr);
+    }
+
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "Child %d made %d of %d calls in %ld sec\n",
+                       Child_num, Ops[TOTAL].results.good_calls,
+                       Ops[TOTAL].target_calls,
+                       Ops[TOTAL].results.time.sec);
+       (void) fflush(stderr);
+    }
+
+    clnt_destroy(NFS_client);
+    biod_term();
+
+    /* write stats to log file (append mode) */
+    report.version = nfs_version;
+    for (i = 0; i < NOPS + 1; i++) {
+       report.results_buf[i] = Ops[i].results;
+    }
+    report.total_fss_bytes = Total_fss_bytes;
+    report.least_fss_bytes = Least_fss_bytes;
+    report.most_fss_bytes = Most_fss_bytes;
+    report.base_fss_bytes = Base_fss_bytes;
+
+    if (write(Log_fd, (char *) &report, sizeof(report)) == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't write to synchronization file %s ",
+                       sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror(Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(149);
+    }
+    (void) close(Log_fd);
+
+    print_dump(Client_num, Child_num);
+
+} /* child */
+
+
+/*
+ * --------------------  Call Target Initialization  --------------------
+ */
+
+/*
+ * Initialize call and request targets.
+ */
+static void
+init_targets(void)
+{
+    int                call_target;            /* total number of calls to make */
+    int                req_target;             /* total number of reqs to make */
+    int32_t    equal_mix;              /* equal mix of operations */
+    int32_t    slack;                  /* calls leftover after % mix */
+    int                randnum;                /* a random number */
+    int32_t    i;                      /* general use */
+    double     total_req_pcnt;
+    double     previous_pcnt;
+    int                nops_used = 0;
+
+
+    /*
+     * Compute number of target calls for each operation.
+     * These are used to estimate the number of filehandles
+     * that will be used for each type of operation.
+     */
+    call_target = Ops[TOTAL].target_calls;
+    Ops[TOTAL].target_calls = 0;
+
+    for (i = 0; i < NOPS; i++) {
+       Ops[i].target_calls = (Ops[i].mix_pcnt * call_target) / 100;
+       Ops[TOTAL].target_calls += Ops[i].target_calls;
+       if (Ops[i].mix_pcnt != 0)
+           nops_used++;
+    }
+
+    /* Put left over calls into the heavier mix operations. */
+    slack = call_target - Ops[TOTAL].target_calls;
+    equal_mix =  (100 / nops_used) / 2;
+    while (slack > 0) {
+       randnum = sfs_random() % NOPS;
+       if (Ops[randnum].mix_pcnt != 0 && Ops[randnum].mix_pcnt >= equal_mix) {
+           Ops[randnum].target_calls++;
+           Ops[TOTAL].target_calls++;
+           slack--;
+       }
+    }
+
+    /*
+     * compute request targets (based on suggestions from M. Molloy, HP)
+     */
+
+    /* compute total of target requests, based on weighted ops */
+    total_req_pcnt = 0.0;
+    for (i = 0; i < NOPS ; i++) {
+       switch (i) {
+       case READ:
+           total_req_pcnt += ((double) Ops[i].mix_pcnt)
+                           / Io_dist_ptr->avg_ops_per_read_req;
+           break;
+       case WRITE:
+           total_req_pcnt += ((double) Ops[i].mix_pcnt)
+                           / Io_dist_ptr->avg_ops_per_write_req;
+           break;
+       case COMMIT:    /* Commits never generate requests */
+           break;
+       default:
+           total_req_pcnt += (double) Ops[i].mix_pcnt;
+           break;
+       }
+    }
+
+    /*
+     * compute cumulative frequency distribution percentile for each op.
+     * This code assumes that the NULLCALL does not generate multiple
+     * OTW operations per request.
+     */
+    previous_pcnt = 0.0;
+    for (i = 0; i < NOPS; i++) {
+       switch (i) {
+       case READ:
+           Ops[i].req_pcnt = previous_pcnt +
+                             (((100.0 * (double) Ops[i].mix_pcnt)
+                             / Io_dist_ptr->avg_ops_per_read_req)
+                             / total_req_pcnt);
+           break;
+       case WRITE:
+           Ops[i].req_pcnt = previous_pcnt +
+                             (((100.0 * (double) Ops[i].mix_pcnt)
+                             / Io_dist_ptr->avg_ops_per_write_req)
+                             / total_req_pcnt);
+           break;
+       case COMMIT:    /* Commits never generate requests */
+           Ops[i].req_pcnt = previous_pcnt;
+           break;
+       default:
+           Ops[i].req_pcnt = previous_pcnt +
+                             ((100.0 * (double) Ops[i].mix_pcnt)
+                             / total_req_pcnt);
+           break;
+       }
+       previous_pcnt = Ops[i].req_pcnt;
+    }
+    /* force last bucket to 100 */
+    Ops[NOPS-1].req_pcnt = 100;
+
+    /* compute the req load rate */
+    Child_req_load = (total_req_pcnt * Child_call_load) / 100.0;
+
+    /*
+     * Compute number of target reqs for each operation.
+     * These are used for debugging purposes.
+     */
+    req_target = (total_req_pcnt * Ops[TOTAL].target_calls) / 100;
+    Ops[TOTAL].target_reqs = 0;
+
+    previous_pcnt = 0.0;
+    for (i = 0; i < NOPS; i++) {
+       Ops[i].target_reqs = 0;
+       if (Ops[i].mix_pcnt != 0) {
+           Ops[i].target_reqs = ((Ops[i].req_pcnt - previous_pcnt) *
+                                                       req_target) / 100;
+       }
+       Ops[TOTAL].target_reqs += Ops[i].target_reqs;
+       previous_pcnt = Ops[i].req_pcnt;
+    }
+
+    /* Put left over reqs into the heavier mix operations. */
+    slack = req_target - Ops[TOTAL].target_reqs;
+    equal_mix =  (100 / nops_used) / 2;
+    while (slack > 0) {
+       randnum = sfs_random() % NOPS;
+       if (Ops[randnum].target_reqs != 0 &&
+                                       Ops[randnum].req_pcnt >= equal_mix) {
+           Ops[randnum].target_reqs++;
+           Ops[TOTAL].target_reqs++;
+           slack--;
+       }
+    }
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr,
+                       "      Op\t  Op mix\tCalls\t\t Req mix\t Reqs\t\n");
+       previous_pcnt = 0.0;
+       for (i = 0; i < NOPS; i++) {
+           (void) fprintf(stderr, "%8s\t%8d\t%5d\t\t%8.2f\t%5d\n",
+                               Ops[i].name,
+                               Ops[i].mix_pcnt, Ops[i].target_calls,
+                               Ops[i].req_pcnt - previous_pcnt,
+                               Ops[i].target_reqs);
+           previous_pcnt = Ops[i].req_pcnt;
+       }
+    }
+} /* init_targets */
+
+
+/*
+ * -----------------------  File Set Initialization  -----------------------
+ */
+
+static file_array_initialized = 0;
+static int file_size_array[100];
+
+/*
+ * For a value between 0-99, return a size based on distribution
+ */
+static int
+get_file_size(int i)
+{
+    if (i < 0 || i > 99)
+       return (0);
+
+    if (file_array_initialized == 0) {
+       int j, k;
+
+       for (j = 0, k = 0; j < 100; j++) {
+           if (j >= Default_file_size_dist[k].pcnt &&
+                       Default_file_size_dist[k + 1].size != 0)
+               k++;
+           file_size_array[j] = Default_file_size_dist[k].size * 1024;
+       }
+       file_array_initialized++;
+    }
+    return (file_size_array[i]);
+}
+
+/*
+ * allocate and initialize the various file information structures.
+ */
+void
+init_fileinfo(void)
+{
+    int      i, index;
+    int      j;
+    int      group_size, group_cnt;
+    int      range, previous_range;
+    int      next_value;
+    double   lambda;
+    double   e_to_the_lambda;
+    double   cumulative_ratio;
+    int             num_non_io_to_init;
+    int             io_file_num = 0;
+    int             files_per_generation;
+    sfs_fh_data        *fh_datap;
+
+
+    /*
+     * Zero number of files created used to create unique names
+     */
+    Files_created = 0;
+
+    /*
+     * Dirs - Initialize the files info structure.
+     * Directories must come first, in initializing test dirs we
+     * need to make sure that any files deleted are no full directories
+     */
+    Num_dir_files =
+            Num_dirs +                         /* exist: readdir, rmdir */
+            Ops[MKDIR].target_calls +          /* non-exist: mkdir */
+            Ops[RMDIR].target_calls;           /* empty dir to be removed */
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "%s: allocate %d directories\n",
+                          sfs_Myname, Num_dir_files);
+       (void) fflush(stderr);
+    }
+    Dirs = (sfs_fh_type *) calloc(Num_dir_files, sizeof(sfs_fh_type));
+
+    if (Dirs == (sfs_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo dir calloc %d bytes failed",
+                       sfs_Myname, Num_dir_files * sizeof(sfs_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(150);
+    }
+    for (i = 0; i < Num_dir_files; i++) {
+       Dirs[i].working_set = 0;
+       Dirs[i].state = Nonexistent;
+       if (i <= (Num_dirs + Ops[RMDIR].target_calls)) {
+           Dirs[i].initialize = 1;
+           Dirs[i].fh_data = (sfs_fh_data *)0;
+       }
+       Dirs[i].unique_num = i;
+    }
+
+    /* Working Set Directory Files - Initialize the working files array. */
+    Num_working_dirs = Num_dir_files;
+    Dir_working_set.entries = (sfs_work_fh_type *)
+                             calloc(Num_working_dirs,
+                                    sizeof(sfs_work_fh_type));
+    if (Dir_working_set.entries == (sfs_work_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo wdir calloc %d bytes failed",
+               sfs_Myname, Num_working_dirs * sizeof(sfs_work_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(151);
+    }
+
+    /*
+     * Dirs are accessed uniformly.  See Non_io_files for a description.
+     */
+    if (init_rand_range(Num_dir_files)) {
+       (void) fprintf(stderr, "%s: init_fileinfo dir init_rand_range failed",
+               sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(183);
+    }
+
+    for (i = 0; i < Num_working_dirs; i++) {
+       if (Num_working_dirs != Num_dir_files) {
+           /* generate a random subset */
+           index = rand_range(i);
+       } else {
+           /* match the working set one-to-one with the files */
+           index = i;
+       }
+
+       Dirs[index].working_set = 1;
+       Dir_working_set.entries[i].index = index;
+       Dir_working_set.entries[i].range = i + 1;
+    }
+    Dir_working_set.access_group_size = Num_working_dirs;
+    Dir_working_set.access_group_cnt = 1;
+
+    Dir_working_set.max_range = Num_working_dirs;
+
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "\nDir size=%d cnt=%d max=%d\n",
+                           Dir_working_set.access_group_size,
+                           Dir_working_set.access_group_cnt,
+                           Dir_working_set.max_range);
+       (void) fflush(stderr);
+    }
+
+
+    /*
+     * I/o Files - Initialize the files info structure to Num_io_files.
+     */
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "%s: allocate %d i/o files, %d working\n",
+                          sfs_Myname, Num_io_files, Num_working_io_files);
+       (void) fflush(stderr);
+    }
+
+    Io_files = (sfs_fh_type *) calloc(Num_io_files, sizeof(sfs_fh_type));
+    if (Io_files == (sfs_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo %d io files calloc %d bytes failed",
+                       sfs_Myname, Num_io_files,
+                       Num_io_files * sizeof(sfs_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(152);
+    }
+    io_file_num = 0;
+    for (i = 0; i < Num_io_files; i++) {
+       Io_files[i].working_set = 0;
+       Io_files[i].state = Nonexistent;
+       Io_files[i].initialize = 1;
+       Io_files[i].size = get_file_size(io_file_num % 100);
+       Io_files[i].unique_num = Files_created++;
+       /* Memory allocation for the fh_data will be done later.  */
+       Io_files[i].fh_data = (sfs_fh_data *)0;
+       io_file_num++;
+    }
+
+    /*
+     * Working Set I/o Files - Initialize the working files array.
+     * Only Access_percent of the Io_files are put into the working set.
+     */
+    Io_working_set.entries = (sfs_work_fh_type *)
+                          calloc(Num_working_io_files,
+                                 sizeof(sfs_work_fh_type));
+    if (Io_working_set.entries == (sfs_work_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo wio calloc %d bytes failed",
+               sfs_Myname, Num_working_io_files * sizeof(sfs_work_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(153);
+    }
+
+
+    if (DEBUG_CHILD_FILES) {
+       (void) fprintf(stderr, "working_set: ");
+       (void) fflush(stderr);
+    }
+
+    /*
+     * For now, the access distribution is poisson.  See below.
+     */
+/* #define UNIFORM_ACCESS */
+#define POISSON_ACCESS
+
+#ifdef UNIFORM_ACCESS
+    /*
+     * With a uniform access distribution, there is no need for access
+     * groups.
+     * Hopefully SPEC-SFS will agree on a non-uniform access function.
+     * (see below for an example using a poisson distribution).
+     */
+    if (init_rand_range(Num_io_files)) {
+       (void) fprintf(stderr, "%s: init_fileinfo io init_rand_range failed",
+               sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(184);
+    }
+
+    for (i = 0; i < Num_working_io_files; i++) {
+       if (Num_working_io_files != Num_io_files) {
+           /* generate a random subset */
+           index = rand_range(i);
+       } else {
+           /* match the working set one-to-one with the files */
+           index = i;
+       }
+       Io_files[index].working_set = 1;
+       Io_working_set.entries[i].index = index;
+       Io_working_set.entries[i].range = i + 1;
+
+       if (DEBUG_CHILD_FILES) {
+           (void) fprintf(stderr, "%d,", index);
+           (void) fflush(stderr);
+       }
+    }
+    Io_working_set.access_group_size = Num_working_io_files;
+    Io_working_set.access_group_cnt = 1;
+    Io_working_set.max_range = Num_working_io_files;
+
+    if (DEBUG_CHILD_FILES) {
+       (void) fprintf(stderr, "\nIo size=%d cnt=%d max=%d\n",
+                           Io_working_set.access_group_size,
+                           Io_working_set.access_group_cnt,
+                           Io_working_set.max_range);
+       (void) fflush(stderr);
+    }
+
+#endif /* ! UNIFORM_ACCESS */
+#ifdef POISSON_ACCESS
+
+    /*
+     * The working set is partitioned into access groups of Access_group_size
+     * files.  Each group is assigned a probability of being accessed.
+     * This is implemented as a cumulative distribution table, with
+     * variable probabilities for each group.  The distribution function
+     * is used to generate a sequence of values, one for each group.
+     * Each group is assigned a 'range' value that is the sum of all
+     * previous range values, plus the next value in the distribution
+     * sequence.  Thus, the probability of choosing any particular group
+     * is equal to the relative height of the distribution curve at the
+     * point represented by that group.
+     * The choice is made by generating a random number in the range
+     * 0 up to (the sum of all values in the distribution sequence - 1),
+     * and finding the group with the greatest range value less than
+     * the random number.
+     * Once a group is chosen, a random number in the range
+     * 1 - Access_group_size is used to pick an entry from within the group.
+     * The entry chosen points to a file in the Io_files array.
+     * If the file at Io_files[index] is eligible for the operation,
+     * then it is accessed, otherwise, the access group is searched
+     * sequentially (mod Access_group_size with wrap-around) until an
+     * eligible file is found.
+     * Access_group_size is derived so that there are enough files
+     * in each group to give a good chance of finding an eligible file
+     * for each operation, but so that there are enough groups (each
+     * representing a point on the distribution curve) to generate a
+     * fairly smooth access distribution curve.
+     */
+
+    /*
+     * group_cnt = 8 + ((Num_working_io_files/500) * 4);
+     *
+     * The function is chosen to guarentee that each group contains
+     * at least 1 file, and, beginning with a base of 8 groups, the
+     * number of groups increases by 4 for each 500 files in the working
+     * set.  It was arrived at heuristically.  The goal is to put enough
+     * files into each group to ensure that a file with the right
+     * attributes can be found once the group is selected (which can be
+     * difficult for small working sets), while at the same time creating
+     * enough groups to provide enough points on the distribution curve
+     * to yield an interesting access distribution.
+     *
+     * Since this function is being computed per child, the interesting range
+     * of working set sizes is computed based on a range of per child load
+     * values from 1 op/sec to 100 op/sec.  Note that this assumes an
+     * average server response time of at least 10 msec, which seems to be
+     * a good minimum value for a wide range of servers given the default
+     * mix of NFS operations.
+     * Based on these load values, the total file set, based on the default
+     * values of 10 MB/op and 38 files/MB, works out to 380 - 38000 files.
+     * The default working set of 10% of these files yields a working
+     * set size of 38 - 3800 files.
+     */
+
+     files_per_generation = (_GROUP_DIVISOR * generations) / _FILES_PER_GROUP;
+     Io_working_set.access_group_cnt = generations +
+       ((Num_working_io_files/files_per_generation) * generations);
+    /*
+     * if the number of files in the working set is not a multiple of
+     * the group size, then some groups will contain (group_size+1) files.
+     * Thus, this is the base group size.
+     */
+    Io_working_set.access_group_size = Num_working_io_files /
+                                     Io_working_set.access_group_cnt;
+
+    if (init_rand_range(Num_io_files)) {
+       (void) fprintf(stderr, "%s: init_fileinfo io init_rand_range failed",
+               sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(185);
+    }
+
+    /* randomly set up working set of indices into Io_files */
+    for (i = 0; i < Num_working_io_files; i++) {
+       if (Num_working_io_files != Num_io_files) {
+           /* generate a random subset */
+           index = rand_range(i);
+       } else {
+           /* match the working set one-to-one with the files */
+           index = i;
+       }
+       Io_files[index].working_set = 1;
+       Io_working_set.entries[i].index = index;
+
+       if (DEBUG_CHILD_FILES) {
+           (void) fprintf(stderr, "%d,", index);
+           (void) fflush(stderr);
+       }
+    }
+
+    /* initialization for distribution function */
+    range = 0;
+    lambda = (double) (generations / 2);
+    if (lambda <= 0) lambda = 1;
+    e_to_the_lambda = exp(lambda);
+    cumulative_ratio = 1.0;
+
+    if (DEBUG_CHILD_FILES) {
+       (void) fprintf(stderr,
+                       "\ngrp_cnt %d lambda %6.0f e_to_the_lambda %6.2f\n",
+                       Io_working_set.access_group_cnt, lambda,
+                       e_to_the_lambda);
+       (void) fflush(stderr);
+    }
+
+    /* assign a range to each group */
+    for (i = 0; i < Io_working_set.access_group_cnt; i++) {
+       /*
+        * get next value in poisson distribution sequence, using
+        *    lambda^x / (e^(lambda) * x!) , for x=1,2,3,...,group_cnt
+        */
+        double probability;
+
+       if( i % generations == 0)
+       {
+               lambda = (double) (generations / 2);
+               if (lambda <= 0) lambda = 1;
+                       e_to_the_lambda = exp(lambda);
+               cumulative_ratio = 1.0;
+       }
+        probability = cumulative_ratio/e_to_the_lambda;
+        if (probability <= 0.0 || probability > 1.0) {
+               (void) fprintf(stderr, "%s: access probability = %g while setting up Io_working_set, i=%d of %d\n",
+                       sfs_Myname, probability,
+                       i, Io_working_set.access_group_cnt);
+               (void) generic_kill(0, SIGINT);
+               exit(154);
+        }
+
+       /* convert probability to scaled integer */
+       next_value = (int) (PROB_SCALE * probability);
+
+       /* check for negative numbers */
+        if (next_value <= 0) {
+               (void) fprintf(stderr, "%s: next_value = %d while setting up Io_working_set, i=%d of %d\n",
+                       sfs_Myname, next_value,
+                       i, Io_working_set.access_group_cnt);
+               (void) generic_kill(0, SIGINT);
+               exit(154);
+        }
+
+       previous_range = range;
+       range = previous_range + next_value;
+        if (range <= previous_range || range < 0) {
+               (void) fprintf(stderr, "%s: range = %d previous_range = %d while setting up Io_working_set, i=%d of %d\n",
+                       sfs_Myname, range, previous_range,
+                       i, Io_working_set.access_group_cnt);
+               (void) generic_kill(0, SIGINT);
+               exit(154);
+        }
+
+       /* assign range value to each file in this group */
+       group_size = Io_working_set.access_group_size;
+       group_cnt = Io_working_set.access_group_cnt;
+       if (i < (Num_working_io_files -
+                ((Num_working_io_files / group_cnt) * group_cnt)))
+           group_size += 1;
+       for (j = 0; j < group_size; j++) {
+           index = i + (j * Io_working_set.access_group_cnt);
+           Io_working_set.entries[index].range = range;
+       }
+
+       cumulative_ratio *= lambda / (double) ((i%generations)+1);
+
+       if (DEBUG_CHILD_SETUP) {
+           (void) fprintf(stderr, "group %d next %d range %d\n",
+                               i, next_value, range);
+           (void) fflush(stderr);
+       }
+    }
+    Io_working_set.max_range = range;
+
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "\nIo size=%d cnt=%d max=%d\n",
+                          Io_working_set.access_group_size,
+                          Io_working_set.access_group_cnt,
+                          Io_working_set.max_range);
+       (void) fflush(stderr);
+    }
+#endif /* POISSON_ACCESS */
+
+
+     /* figure out how many files to allocate and initialize */
+
+    /* initialize half the non-I/O files */
+    /* NOTE: initializing half the non-i/o files works ok with the
+            default op mix.  If the mix is changed affecting the
+            ratio of creations to removes, there may not be enough
+            empty slots for file creation (or there may not be
+            enough created during initialization to handle a lot of
+            removes that occur early in the test run), and this would
+            cause do_op() to fail to find a file appropriate for the
+            chosen op.  This will result in the global variable
+            Ops[op].no_calls being incremented (turn on child level
+            debugging to check this count), and the do_op() local
+            variable aborted_ops to be incremented and checked during
+            runtime for too many failures.
+     */
+    num_non_io_to_init = Num_non_io_files * RATIO_NON_IO_INIT;
+
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "%s: allocate %d non-i/o files\n",
+                           sfs_Myname, Num_non_io_files);
+       (void) fflush(stderr);
+    }
+    Non_io_files = (sfs_fh_type *)
+                   calloc(Num_non_io_files, sizeof(sfs_fh_type));
+    if (Non_io_files == (sfs_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo nio calloc %d bytes failed",
+               sfs_Myname, Num_non_io_files * sizeof(sfs_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(154);
+    }
+    for (i = 0; i < Num_non_io_files; i++) {
+       Non_io_files[i].working_set = 0;
+       Non_io_files[i].state = Nonexistent;
+        if (i <= num_non_io_to_init)
+           Non_io_files[i].initialize = 1;
+       Non_io_files[i].size = get_file_size(io_file_num % 100);
+       Non_io_files[i].unique_num = Files_created++;
+       /* Allocation of fh_data will happen in init_testdir */
+       Non_io_files[i].fh_data = (sfs_fh_data *)0;
+       io_file_num++;
+    }
+
+    /* Working Set Non i/o Files - Initialize the working files array. */
+    Num_working_non_io_files = Num_non_io_files;
+    Non_io_working_set.entries = (sfs_work_fh_type *)
+                                calloc(Num_working_non_io_files,
+                                       sizeof(sfs_work_fh_type));
+    if (Non_io_working_set.entries == (sfs_work_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo nwio calloc %d bytes failed",
+               sfs_Myname, Num_working_io_files * sizeof(sfs_work_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(155);
+    }
+
+    /*
+     * Non_io_files are accessed uniformly.  Each entry has a
+     * 1/Num_working_non_io_files change of being accessed.
+     * The choice is made by generating a random number in the range
+     * 0 through (Num_working_non_io_files - 1) and finding the entry
+     * with the greatest range value less than the random number.
+     * If the file at Non_io_files[index] is eligible for the operation,
+     * it is accessed, otherwise, the access group that the entry belongs
+     * to is searched sequentially until an eligible file is found.
+     * For non i/o files, all of the working set files are in the same
+     * access group (since they access is uniform, this is ok, and
+     * maximizes the chances of finding an eligible file).
+     */
+    if (init_rand_range(Num_non_io_files)) {
+       (void) fprintf(stderr, "%s: init_fileinfo non_io init_rand_range failed",
+               sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(186);
+    }
+
+    for (i = 0; i < Num_working_non_io_files; i++) {
+       if (Num_working_non_io_files != Num_non_io_files) {
+           /* generate a random subset */
+           index = rand_range(i);
+       } else {
+           /* match the working set one-to-one with the files */
+           index = i;
+       }
+       Non_io_files[index].working_set = 1;
+       Non_io_working_set.entries[i].index = index;
+       Non_io_working_set.entries[i].range = i + 1;
+    }
+    Non_io_working_set.access_group_size = Num_working_non_io_files;
+    Non_io_working_set.access_group_cnt = 1;
+    Non_io_working_set.max_range = Num_working_non_io_files;
+
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "\nNon_io        size=%d cnt=%d max=%d\n",
+                           Non_io_working_set.access_group_size,
+                           Non_io_working_set.access_group_cnt,
+                           Non_io_working_set.max_range);
+       (void) fflush(stderr);
+    }
+
+
+    /* Symlinks - Initialize the files info structure. */
+    Num_symlink_files =
+            Num_symlinks +                     /* exist: readlink */
+            Ops[SYMLINK].target_calls;         /* non-exist: symlink */
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "%s: allocate %d symlinks\n",
+                          sfs_Myname, Num_symlink_files);
+       (void) fflush(stderr);
+    }
+    Symlinks = (sfs_fh_type *)
+               calloc(Num_symlink_files, sizeof(sfs_fh_type));
+    if (Symlinks == (sfs_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo sym calloc %d bytes failed",
+                       sfs_Myname, (Num_symlink_files * sizeof(sfs_fh_type)));
+       (void) generic_kill(0, SIGINT);
+       exit(156);
+    }
+    for (i = 0; i < Num_symlink_files; i++) {
+       Symlinks[i].working_set = 0;
+       Symlinks[i].state = Nonexistent;
+       if (i <= Num_symlinks)
+           Symlinks[i].initialize = 1;
+       Symlinks[i].fh_data = (sfs_fh_data *)0;
+       Symlinks[i].unique_num = i;
+    }
+
+    /* Working Set Symlinks - Initialize the working files array. */
+    /* This appears to cause the following loop to be mostly dead */
+    /* code.  It is unclear why this line is here. One */
+    /* possibility is that Num_symlink_files should be */
+    /* Num_symlinks.  XXX */
+    Num_working_symlinks = Num_symlink_files;
+    Symlink_working_set.entries = (sfs_work_fh_type *)
+                                 calloc(Num_working_symlinks,
+                                        sizeof(sfs_work_fh_type));
+    if (Symlink_working_set.entries == (sfs_work_fh_type *) 0) {
+       (void) fprintf(stderr,"%s: init_fileinfo wsym calloc %d bytes failed",
+               sfs_Myname, Num_working_symlinks * sizeof(sfs_work_fh_type));
+       (void) generic_kill(0, SIGINT);
+       exit(157);
+    }
+
+    /*
+     * Symlinks are accessed uniformly.  See Non_io_files for a description.
+     */
+    if (init_rand_range(Num_symlink_files)) {
+       (void) fprintf(stderr, "%s: init_fileinfo sym init_rand_range failed",
+               sfs_Myname);
+       (void) generic_kill(0, SIGINT);
+       exit(187);
+    }
+
+    for (i = 0; i < Num_working_symlinks; i++) {
+       if (Num_working_symlinks != Num_symlink_files) {
+           /* generate a random subset */
+           index = rand_range(i);
+       } else {
+           /* match the working set one-to-one with the files */
+           index = i;
+       }
+
+       Symlinks[index].working_set = 1;
+       Symlink_working_set.entries[i].index = index;
+       Symlink_working_set.entries[i].range = i + 1;
+    }
+    Symlink_working_set.access_group_size = Num_working_symlinks;
+    Symlink_working_set.access_group_cnt = 1;
+    Symlink_working_set.max_range = Num_working_symlinks;
+
+    if (DEBUG_CHILD_SETUP) {
+       (void) fprintf(stderr, "\nSymlink size=%d cnt=%d max=%d\n",
+                           Symlink_working_set.access_group_size,
+                           Symlink_working_set.access_group_cnt,
+                           Symlink_working_set.max_range);
+       (void) fflush(stderr);
+    }
+
+    /*
+     * Free up random number range
+     */
+    (void)init_rand_range(0);
+
+
+} /* init_fileinfo */
+
+/*
+ * allocate and initialize the directory layout of the files
+ *
+ * We can only place files in directories that can't be removed
+ */
+static void
+init_dirlayout(void)
+{
+    int i,j;
+
+    /*
+     * Initially create directories only one level deep so all directories
+     * must be in the parent directory.
+     */
+    for (i = 0; i < Num_dir_files; i++) {
+       Dirs[i].dir = &Export_dir;
+    }
+
+    /*
+     * Files must only be placed in the first Num_dirs entries leaving
+     * a set for directory create and remove.
+     */
+    j = 0;
+    for (i = 0; i < Num_io_files; i++) {
+       if (i != 0 && (i % Files_per_dir) == 0)
+               j++;
+       Io_files[i].dir = &Dirs[j];
+    }
+
+    /*
+     * All non-io and symlink files are placed in the parent directory
+     */
+    for (i = 0; i < Num_non_io_files; i++) {
+       Non_io_files[i].dir = &Export_dir;
+    }
+
+    for (i = 0; i < Num_symlink_files; i++) {
+       Symlinks[i].dir = &Export_dir;
+    }
+}
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+    /* Initialize biod simulation mechanism if desired.  */
+    if (Biod_max_outstanding_reads > 0 || Biod_max_outstanding_writes > 0) {
+       if (biod_init(Biod_max_outstanding_writes,
+               Biod_max_outstanding_reads) == -1) {
+           return(-1);
+       }
+    }
+
+    return(0);
+} /* init_rpc */
+
+/*
+ * Initialize the test directory 'parentdir'/testdir'dirnum'.
+ *
+ * If the directory already exists, check to see that all of the
+ * files exist and can be written.  If the directory doesn't exist
+ * create it and fill it with the proper files.  The caller is
+ * left with his cwd being the test directory.
+ *
+ * Each child pseudo-mount's his own test directory to get its filehandle.
+ *
+ * Files, directories, and symlinks all have the same name structure
+ * but they are strictly ordered, files first, directories next, then symlinks.
+ * While initializing after a previous run we may have to delete existing
+ * files of the wrong type and then create them later.
+ *
+ * XXX In the future it is probably wiser to have seperate namespaces for
+ * each type of file.
+ */
+static void
+init_testdir(void)
+{
+    int                        filenum;
+    int                        max_filenum;
+    int                        init_size;
+    int                        append_size;
+    int                        ret;
+    int                        non = 0;
+    int                dealloc;
+    int                        alloc_count, dealloc_count;
+    /*
+     * Create directories first so operations that
+     * require them will have a file to work with.
+     */
+    alloc_count=dealloc_count=0;
+    for (filenum = 0; filenum < Num_dir_files; filenum++) {
+       sfs_gettime(&Cur_time);
+
+       Cur_file_ptr = &Dirs[filenum];
+       dealloc=0;
+       if(Cur_file_ptr->fh_data == (sfs_fh_data *)0)
+       {
+               alloc_count++;
+               Cur_file_ptr->fh_data = calloc(1,sizeof(sfs_fh_data));
+               Cur_file_ptr->attributes2.type = NFNON;
+               Cur_file_ptr->attributes3.type = NF3NON;
+               if(Cur_file_ptr->working_set == 1)
+                       dealloc=0;
+               else
+                       dealloc=1;
+       }
+
+       (void) sprintf(Cur_filename, Dirspec, Cur_file_ptr->unique_num);
+
+       if (DEBUG_CHILD_SETUP) {
+           (void) fprintf(stderr, "%s: initialize %s (DIR)\n",
+                                  sfs_Myname, Cur_filename);
+           (void) fflush(stderr);
+       }
+
+       if ((ret = lad_lookup(Cur_file_ptr, Cur_filename)) == -1) {
+           /* some error that I don't know what to do with, quit. */
+           (void) generic_kill(0, SIGINT);
+           exit(159);
+       }
+
+       if (ret == 0) {
+           /* file exists */
+           if (fh_isdir(Cur_file_ptr) && Cur_file_ptr->initialize)
+           {
+               if(dealloc == 1)
+               {
+                       dealloc_count++;
+                       free(Cur_file_ptr->fh_data);
+                       Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+               }
+               continue;
+           }
+
+           if (lad_remove(Cur_file_ptr, Cur_filename) != 0) {
+               /* some error that I don't know what to do with, quit. */
+               (void) generic_kill(0, SIGINT);
+               exit(160);
+           }
+        }
+
+       if (!Cur_file_ptr->initialize) {
+               /* dir shouldn't exist */
+           if(dealloc == 1)
+            {  
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+            }
+           continue;
+       }
+
+       /* make the directory */
+       if (lad_mkdir(Cur_file_ptr, Cur_filename) == -1) {
+           /* some error that I don't know what to do with, quit. */
+           (void) generic_kill(0, SIGINT);
+           exit(161);
+       }
+       if(dealloc == 1)
+       {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+       }
+    } /* end for each directory */
+
+    /*
+     * Setup for file i/o operations.
+     * Verify that we can read and write all the files.
+     * Make sure we have the attributes && fh for all regular files.
+     * Create any missing files.
+     */
+    max_filenum = Num_io_files + Num_non_io_files;
+    alloc_count=dealloc_count=0;
+    for (filenum = 0; filenum < max_filenum; filenum++) {
+       sfs_gettime(&Cur_time);
+
+       if (filenum < Num_io_files) {
+           Cur_file_ptr = &Io_files[filenum];
+       } else {
+           Cur_file_ptr = &Non_io_files[filenum - Num_io_files];
+           non = 1;
+       }
+       (void) sprintf(Cur_filename, Filespec, Cur_file_ptr->unique_num);
+       dealloc=0;
+       if(Cur_file_ptr->fh_data == (sfs_fh_data *)0)
+       {
+               alloc_count++;
+               Cur_file_ptr->fh_data = calloc(1,sizeof(sfs_fh_data));
+               Cur_file_ptr->attributes2.type = NFNON;
+               Cur_file_ptr->attributes3.type = NF3NON;
+               if(Cur_file_ptr->working_set == 1)
+                       dealloc=0;
+               else
+                       dealloc=1;
+       }
+
+       /*
+        * Get the size this file should be initialized to, then reset
+        * so we don't get confused.
+        */
+       init_size = Cur_file_ptr->size;
+       Cur_file_ptr->size = 0;
+
+       if (DEBUG_CHILD_SETUP) {
+           (void) fprintf(stderr, "%s: initialize %s (REG for %sIO)\n",
+                                  sfs_Myname, Cur_filename,
+                                  (non ? "non-": ""));
+           (void) fflush(stderr);
+       }
+
+       if ((ret = lad_lookup(Cur_file_ptr, Cur_filename)) == -1) {
+           /* some error that I don't know what to do with, quit. */
+           (void) generic_kill(0, SIGINT);
+           exit(162);
+       }
+
+       if (ret == 0) {
+           /*
+            * If file exists and it shouldn't, remove it
+            */
+           if (!Cur_file_ptr->initialize) {
+               if (lad_remove(Cur_file_ptr, Cur_filename) != 0) {
+                   /* some error that I don't know what to do with, quit. */
+                   (void) generic_kill(0, SIGINT);
+                   exit(163);
+               }
+               if(dealloc == 1)
+               {
+                       dealloc_count++;
+                       free(Cur_file_ptr->fh_data);
+                       Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+               }
+               continue;
+           }
+
+           /*
+            * file exists: make sure it is
+            *  - a regular file
+            *  - accessible (permissions ok)
+            * if not, remove it (if necessary) and recreate it
+            * or extend or truncate it to the standard length.
+            */
+           if (fh_isfile(Cur_file_ptr) &&
+                               check_fh_access(Cur_file_ptr) == 0) {
+               goto adjust_size;
+           }
+           if (lad_remove(Cur_file_ptr, Cur_filename) != 0) {
+               /* some error that I don't know what to do with, quit. */
+               (void) generic_kill(0, SIGINT);
+               exit(164);
+           }
+
+       } /* end if the file exists */
+
+       /* the file doesn't exist */
+       if (!Cur_file_ptr->initialize) {
+           /* file doesn't exist and it shouldn't */
+           if(dealloc == 1)
+           {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+           }
+           continue;
+       }
+
+       /* if the file doesn't exist (or was removed), create it */
+       if (lad_create(Cur_file_ptr, Cur_filename) == -1) {
+           /* some error that I don't know what to do with, quit. */
+           (void) generic_kill(0, SIGINT);
+           exit(165);
+       }
+
+adjust_size:
+       /* the non-i/o regular files can be left empty */
+       if (filenum >= Num_io_files) {
+           /* Truncate if it has grown */
+           if (fh_size(Cur_file_ptr) != 0) {
+               if (lad_truncate(Cur_file_ptr, 0)) {
+                   /* some error that I don't know what to do with, quit. */
+                   (void) generic_kill(0, SIGINT);
+                   exit(166);    
+               }
+           }
+           if(dealloc == 1)
+           {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+           }
+           continue;
+        }     
+
+       /* the i/o file must be prefilled, check if file too big */
+       if (fh_size(Cur_file_ptr) > init_size) {
+           /* Truncate if it has grown */
+           if (fh_size(Cur_file_ptr) != 0) {
+               if (lad_truncate(Cur_file_ptr, init_size)) {
+                   /* some error that I don't know what to do with, quit. */
+                   (void) generic_kill(0, SIGINT);
+                   exit(167);    
+               }
+           }
+           if(dealloc == 1)
+           {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+           }
+           continue;
+       }
+
+       /* the i/o file must be prefilled, set up the write arguments. */
+       if (fh_size(Cur_file_ptr) < init_size) {
+           append_size = init_size - fh_size(Cur_file_ptr);
+
+           if (lad_write(Cur_file_ptr, fh_size(Cur_file_ptr), append_size)) {
+               /* some error that I don't know what to do with, quit. */
+               (void) generic_kill(0, SIGINT);
+               exit(168);
+           }
+       }
+       if(dealloc == 1)
+       {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+       }
+    } /* end for each regular file */
+
+    /*
+     * Create symlinks so operations that
+     * require them will have a file to work with.
+     */
+    alloc_count=dealloc_count=0;
+    for (filenum = 0; filenum < Num_symlink_files; filenum++) {
+       char    symlink_target[SFS_MAXNAMLEN];
+
+       sfs_gettime(&Cur_time);
+
+       Cur_file_ptr = &Symlinks[filenum];
+       (void) sprintf(Cur_filename, Symspec, Cur_file_ptr->unique_num);
+
+       dealloc=0;
+       if(Cur_file_ptr->fh_data == (sfs_fh_data *)0)
+       {
+               alloc_count++;
+               Cur_file_ptr->fh_data = calloc(1,sizeof(sfs_fh_data));
+               Cur_file_ptr->attributes2.type = NFNON;
+               Cur_file_ptr->attributes3.type = NF3NON;
+               if(Cur_file_ptr->working_set == 1)
+                       dealloc=0;
+               else
+                       dealloc=1;
+       }
+       if (DEBUG_CHILD_SETUP) {
+           (void) fprintf(stderr, "%s: initialize %s (SYMLINK)\n",
+                                  sfs_Myname, Cur_filename);
+           (void) fflush(stderr);
+       }
+
+       if ((ret = lad_lookup(Cur_file_ptr, Cur_filename)) == -1) {
+           /* some error that I don't know what to do with, quit. */
+           (void) generic_kill(0, SIGINT);
+           exit(169);
+       }
+
+       if (ret == 0) {
+           /* file exists */
+           if (lad_remove(Cur_file_ptr, Cur_filename) != 0) {
+               /* some error that I don't know what to do with, quit. */
+               (void) generic_kill(0, SIGINT);
+               exit(170);
+           }
+        }
+       
+       /* File doesn't exist */
+       if (Cur_file_ptr->initialize) {
+               /* make the symlink */
+           (void) sprintf(symlink_target, Filespec, filenum);
+           if (lad_symlink(Cur_file_ptr, symlink_target, Cur_filename) != 0) {
+               /* some error that I don't know what to do with, quit. */
+               (void) generic_kill(0, SIGINT);
+               exit(171);
+           }
+       }
+       if(dealloc == 1)
+       {
+               dealloc_count++;
+               free(Cur_file_ptr->fh_data);
+               Cur_file_ptr->fh_data=(sfs_fh_data *)0;
+       }
+    } /* end for each symlink */
+} /* init_testdir */
+
+/*
+ * Initialize the test results counters.
+ */
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize use count for each file */
+    for (i = 0; i < Num_io_files; i++) {
+       Io_files[i].use_cnt = 0;
+       Io_files[i].xfer_cnt = 0;
+    }
+    for (i = 0; i < Num_non_io_files; i++)
+       Non_io_files[i].use_cnt = 0;
+    for (i = 0; i < Num_dir_files; i++)
+       Dirs[i].use_cnt = 0;
+    for (i = 0; i < Num_symlink_files; i++)
+       Symlinks[i].use_cnt = 0;
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+
+
+/*
+ * -------------------------  Load Generation  -------------------------
+ */
+
+/*
+ * The routines below attempt to do over-the-wire operations.
+ * Each op tries to cause one or more of a particular
+ * NFS operation to go over the wire.  Each individual op routine
+ * returns how many OTW calls were made.
+ *
+ * An array of file information is kept for files existing in
+ * the test directory.  File handles, attributes, names, etc
+ * are stored in this array.
+ *
+ */
+
+
+#define        OP_ABORTED      (-1)
+#define        OP_BORROWED     (-2)
+#define        OP_SKIPPED      (-3)
+/*
+ * Randomly perform an operation according to the req mix weightings.
+ */
+static int
+do_op(void)
+{
+    double     ratio;
+    int                op_count;
+    int                opnum;
+    int                start_opnum;
+    static int failed_ops = 0;
+    static int aborted_ops = 0;
+    static int borrowed_ops = 0;
+
+    if (Testop != -1) {
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "testop start op=%s\n", Ops[Testop].name);
+       }
+       op_count = op(Testop);
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "end op=%s\n", Ops[Testop].name);
+       }
+       return(op_count);
+    }
+
+    /* get a random number and search the Ops tables for the proper entry */
+    ratio = sfs_random() % 10000;
+    for (opnum = 0; Ops[opnum].req_pcnt <= ratio / 100.0 ; opnum++) {
+           ;
+    }
+
+    /*
+     * If test targeted a a specific number of ops,
+     * and the call would put us over the call target for this op,
+     * search Ops table sequentially for an op that hasn't
+     * reached its target yet
+     */
+    if (!Timed_run) {
+       start_opnum = opnum;
+       for (; Ops[opnum].results.good_calls >= Ops[opnum].target_calls;) {
+           opnum = (opnum + 1) % NOPS;
+           if (opnum == start_opnum)
+               break;
+       }
+    }
+
+    if (DEBUG_CHILD_RPC) {
+       (void) fprintf(stderr, "(%d,%d,%d) ",
+                          Child_num, Ops[TOTAL].results.good_calls, opnum);
+       (void) fflush(stderr);
+    }
+
+    /* attempt the op */
+    op_count = op(opnum);
+
+    /* count the operations as completed or check for too many errors */
+    if (op_count > 0) {
+       Ops[opnum].req_cnt++;
+       Ops[TOTAL].req_cnt++;
+    } else if (op_count == 0) {
+       failed_ops++;
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "Child %d - %d failed %d op\n",
+                          Child_num, failed_ops, opnum);
+           (void) fflush(stderr);
+       }
+       if ((failed_ops % 50) == 0) {
+           (void) fprintf(stderr, "Child %d - %d failed ops\n",
+                          Child_num, failed_ops);
+           (void) fflush(stderr);
+       }
+    } else if (op_count == OP_ABORTED) {
+       aborted_ops++;
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "Child %d - %d aborted %d op\n",
+                          Child_num, aborted_ops, opnum);
+           (void) fflush(stderr);
+       }
+       if ((aborted_ops % 50) == 0) {
+           (void) fprintf(stderr, "Child %d - %d aborted ops\n",
+                          Child_num, aborted_ops);
+           (void) fflush(stderr);
+       }
+    } else if (op_count == OP_BORROWED) {
+       borrowed_ops++;
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "Child %d - %d borrowed %d op\n",
+                          Child_num, borrowed_ops, opnum);
+           (void) fflush(stderr);
+       }
+    } else if (op_count == OP_SKIPPED) {
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "Child %d - skipped %d op\n",
+                          Child_num, opnum);
+           (void) fflush(stderr);
+       }
+    }
+
+    return(op_count);
+
+} /* do_op */
+
+
+/*
+ * Because file sizes are variable in length, it is possible that
+ * a group chosen for a large transfer size may not contain a file
+ * that large.  Loop calling randfh to try and find another group
+ * with a large enough file, but only up to IO_LOOP_MAX times.
+ */
+#define IO_LOOP_MAX 5
+
+/*
+ * Call the RPC operation generator for op 'opnum'.
+ * The return values of the op generator routines is the count
+ * of operations performed.  This routine also returns that count.
+ * A return of 0 means no operation was attempted,
+ * OP_ABORTED (-1) means that the operation failed.
+ * OP_BORROWED (-2) means that the operation was borrowed.
+ * OP_SKIPPED (-3) means that the operation was not done on purpose.
+ */
+static int
+op(
+    int                                opnum)
+{
+    int                                op_count;
+    int                                trunc_count;
+    sfs_io_op_dist_type                *dist;          /* io size distribution */
+    int                                i;
+    int                                ratio;
+    int                                buf_size;
+    int                                frag_size;
+    int                                xfer_size;
+    int                                file_size;
+    int                                trunc_op;
+    uint_t                     append_flag = 0;
+    uint_t                     randfh_flags = 0;
+    char                       *spec;
+    int                                io_loop = 0;
+
+    spec = Filespec;
+
+    /* pick a file that make sense for the operation */
+    switch (opnum) {
+
+       case NULLCALL:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case GETATTR:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case SETATTR:
+           if (Setattr_borrowed != 0) {
+               Setattr_borrowed--;
+               return(OP_BORROWED);
+           }
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case ROOT:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_non_io_file);
+           break;
+
+       case LOOKUP:
+           ratio = (int) (sfs_random() % 100);
+           if (ratio < Num_failed_lookup)
+               Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_non_io_file);
+           else
+               Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case READLINK:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_symlink);
+           spec = Symspec;
+           break;
+
+       case READ:
+           /* special handling for i/o operations */
+           dist = Io_dist_ptr->read;
+
+           /* determine number of full buffers and their total size */
+           ratio = (sfs_random() % 100);
+           for (i = 0; dist[i].pcnt <= ratio; i++)
+               ;
+           buf_size = dist[i].bufs * Bytes_per_block;
+
+           /* determine size of fragment */
+           /* 1KB - (Kb_per_block - 1) KB fragment */
+           ratio = sfs_random();
+           if (Kb_per_block > 1)
+               ratio = ratio % (Kb_per_block-1);
+           else
+               ratio = 0;
+           ratio = (ratio + 1) * 1024;
+           frag_size = dist[i].frags * ratio;
+
+           xfer_size = buf_size + frag_size;
+
+           do {
+               Cur_file_ptr = randfh(opnum, xfer_size, 0, Exists,
+                                 Sfs_io_file);
+           } while (Cur_file_ptr == (sfs_fh_type *) -1 &&
+                                               io_loop++ < IO_LOOP_MAX);
+           break;
+
+       case WRCACHE:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_non_io_file);
+           break;
+
+       case WRITE:
+           /* special handling for i/o operations */
+           dist = Io_dist_ptr->write;
+
+           /* determine number of full buffers and their total size */
+           ratio = (sfs_random() % 100);
+           for (i = 0; dist[i].pcnt <= ratio; i++)
+               ;
+           buf_size = dist[i].bufs * Bytes_per_block;
+
+           /* determine size of fragment */
+           /* 1KB - (Kb_per_block - 1) KB fragment */
+           ratio = sfs_random();
+           if (Kb_per_block > 1)
+               ratio = ratio % (Kb_per_block-1);
+           else
+               ratio = 0;
+           ratio = (ratio + 1) * 1024;
+           frag_size = dist[i].frags * ratio;
+
+           xfer_size = buf_size + frag_size;
+
+           /* decide if it should append or overwrite. */
+           ratio = (sfs_random() % 100);
+           if (ratio < Append_percent) {
+               append_flag = 1;
+               randfh_flags &= RANDFH_APPEND;
+           }
+
+           /* decide if a truncation will be needed */
+           if (append_flag &&
+                   ((Cur_fss_bytes + (xfer_size / 1024)) > Limit_fss_bytes)) {
+               randfh_flags &= RANDFH_TRUNC;
+           }
+
+           do {
+               Cur_file_ptr = randfh(opnum, xfer_size,
+                                 randfh_flags,
+                                 Exists, Sfs_io_file);
+           } while (Cur_file_ptr == (sfs_fh_type *) -1 &&
+                                               io_loop++ < IO_LOOP_MAX);
+           break;
+
+       case CREATE:
+           if (Create_borrowed != 0) {
+               Create_borrowed--;
+               return(OP_BORROWED);
+           }
+           if ((Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent,
+                             Sfs_non_io_file)) != (sfs_fh_type *) NULL)
+               break;
+
+           /* if there are no Nonexistent files, use one that exists */
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists,
+                                         Sfs_non_io_file);
+           /* flag create of existing file for data dump interface */
+           dump_create_existing_file = TRUE;
+           break;
+
+       case REMOVE:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_non_io_file);
+           break;
+
+       case RENAME:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_non_io_file);
+           break;
+
+       case LINK:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent,
+                                 Sfs_non_io_file);
+           break;
+
+       case SYMLINK:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_symlink);
+           spec = Symspec;
+           break;
+
+       case MKDIR:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_dir);
+           spec = Dirspec;
+           break;
+
+       case RMDIR:
+           Cur_file_ptr = randfh(opnum, 0, 0, Empty_dir, Sfs_dir);
+           spec = Dirspec;
+           break;
+
+       case READDIR:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_dir);
+           spec = Dirspec;
+           break;
+
+       case FSSTAT:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case ACCESS:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_io_file);
+           break;
+
+       case COMMIT:
+           return(OP_SKIPPED);
+
+       case FSINFO:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_non_io_file);
+           break;
+
+       case MKNOD:
+           Cur_file_ptr = randfh(opnum, 0, 0, Nonexistent, Sfs_non_io_file);
+           break;
+
+       case PATHCONF:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_non_io_file);
+           break;
+
+       case READDIRPLUS:
+           Cur_file_ptr = randfh(opnum, 0, 0, Exists, Sfs_dir);
+           spec = Dirspec;
+           break;
+
+       default:
+           (void) fprintf(stderr, "%s: invalid operation %d\n", sfs_Myname, opnum);
+           (void) generic_kill(0, SIGINT);
+           exit(172);
+    } /* switch on opnum */
+
+    if (Cur_file_ptr == (sfs_fh_type *) NULL ||
+                               Cur_file_ptr == (sfs_fh_type *) -1) {
+       Ops[opnum].no_calls++;
+       return(OP_ABORTED);
+    }
+
+    (void) sprintf(Cur_filename, spec, Cur_file_ptr->unique_num);
+
+    /* Call the op routine.  For io operations, maintain file set size info. */
+    switch (opnum) {
+
+       case SETATTR:
+           op_count = (*Ops[opnum].funct)(-1);
+           break;
+
+       case READ:
+           op_count = (*Ops[opnum].funct)(xfer_size);
+           if (op_count > 0)
+               Cur_file_ptr->xfer_cnt += (xfer_size + 1023)  / 1024;
+           else if (DEBUG_CHILD_ERROR) {
+               (void) fprintf(stderr, "%s: READ failed\n", sfs_Myname);
+               (void) fflush(stderr);
+           }
+           break;
+
+       case WRITE:
+           trunc_count = 0;
+
+           /* if appending, we may need to truncate the file first */
+           if (append_flag &&
+                   ((Cur_fss_bytes + (xfer_size / 1024)) > Limit_fss_bytes)) {
+
+               /* use either SETATTR or CREATE for truncation */
+               file_size = fh_size(Cur_file_ptr);
+               trunc_op = -1; /* assume there are no ops to borrow */
+
+               if (Ops[SETATTR].mix_pcnt == 0 && Ops[CREATE].mix_pcnt == 0)
+                   trunc_op = -1;              /* no ops to borrow */
+
+               else if (Ops[SETATTR].mix_pcnt > 0 && Ops[CREATE].mix_pcnt > 0){
+                   /* only borrow if the target hasn't been met yet */
+                   if (Ops[SETATTR].results.good_calls
+                       >= Ops[SETATTR].target_calls) {
+                       if (Ops[CREATE].results.good_calls
+                           < Ops[CREATE].target_calls) {
+                           trunc_op = CREATE;          /* borrow a CREATE */
+                       }
+                   } else if (Ops[CREATE].results.good_calls
+                              >= Ops[CREATE].target_calls) {
+                       trunc_op = SETATTR;             /* borrow a SETATTR */
+                   } else {
+                       /* borrow weighted by mix percentage */
+                       if ((Ops[SETATTR].mix_pcnt * Create_borrowed) >
+                           (Ops[CREATE].mix_pcnt * Setattr_borrowed))
+                           trunc_op =  SETATTR;
+                       else
+                           trunc_op =  CREATE;
+                   }
+
+               } else if (Ops[SETATTR].results.good_calls <
+                          Ops[SETATTR].target_calls) {
+                   /* only borrow if the target hasn't been met yet */
+                   trunc_op = SETATTR;         /* borrow a SETATTR */
+
+               } else if (Ops[CREATE].results.good_calls <
+                          Ops[CREATE].target_calls) {
+                   /* only borrow if the target hasn't been met yet */
+                   trunc_op = CREATE;          /* borrow a CREATE */
+               }
+
+               /* perform the truncation and update the file set size */
+               if (trunc_op != -1) {
+                   dump_truncate_op = TRUE;
+                   if (trunc_op == SETATTR) {
+                       trunc_count = (*Ops[SETATTR].funct)(0);
+                       if (trunc_count > 0) {
+                           Setattr_borrowed++;
+                           if (DEBUG_CHILD_FILES) {
+                               (void) fprintf(stderr, "%s: SETATTR TRUNCATE\n",
+                                               sfs_Myname);
+                               (void) fflush(stderr);
+                           }
+                       }
+                   } else if (trunc_op == CREATE) {
+                       trunc_count = (*Ops[CREATE].funct)();
+                       if (trunc_count > 0) {
+                           Create_borrowed++;
+                           if (DEBUG_CHILD_FILES) {
+                               (void) fprintf(stderr, "%s: CREATE TRUNCATE\n",
+                                           sfs_Myname);
+                               (void) fflush(stderr);
+                           }
+                       }
+                   }
+
+                   Cur_fss_bytes -= (file_size / 1024);
+                   if (Cur_fss_bytes < Least_fss_bytes)
+                       Least_fss_bytes = Cur_fss_bytes;
+               }
+           } /* end of if an append is needed */
+
+           /*
+            * do the write request
+            * specify the stable flag to always be off, it is not used
+            * with V2 servers.
+            */
+           op_count = (*Ops[opnum].funct)(xfer_size, append_flag, 0);
+           if (op_count > 0)
+               Cur_file_ptr->xfer_cnt += (xfer_size + 1023)  / 1024;
+           else if (DEBUG_CHILD_ERROR) {
+               (void) fprintf(stderr, "%s: WRITE failed\n", sfs_Myname);
+               (void) fflush(stderr);
+           }
+           if (append_flag) {
+               Cur_fss_bytes += (xfer_size / 1024);
+               if (Cur_fss_bytes > Most_fss_bytes)
+                   Most_fss_bytes = Cur_fss_bytes;
+           }
+           op_count += trunc_count;
+           break;
+
+       default:
+           op_count = (*Ops[opnum].funct)();
+           break;
+
+    } /* send switch on opnum */
+
+    if ((DEBUG_CHILD_ERROR) && (op_count <= 0)) {
+       (void) fprintf(stderr, "%s: OP %d failed\n", sfs_Myname, opnum);
+       (void) fflush(stderr);
+    }
+
+    return(op_count);
+
+} /* op */
+
+
+/*
+ * Return an entry into the fh array for a file of type 'file_type'
+ * with existence state 'file_state'.  When 'opnum' specifies an I/O
+ * operation, the file must be atleast 'xfer_size' bytes long
+ * (except when 'append_flag' is true).  If 'trunc_flag', spare the
+ * first file found that is longer than the base file size (to support
+ * the READ operation).  If only one file is longer than the base file
+ * size, return the the next longest file.
+ */
+sfs_fh_type *
+randfh(
+    int                                opnum,
+    int                                xfer_size,
+    uint_t                     flags,
+    sfs_state_type             file_state,
+    sfs_file_type              file_type)
+{
+    sfs_fh_type *      files;          /* file array */
+    int                        fh;             /* index into file array */
+    int                        found_fh = -1;  /* index into file array */
+    uint_t             append_flag = flags & RANDFH_APPEND;
+    uint_t             trunc_flag = flags & RANDFH_TRUNC;
+
+    sfs_work_set_type * work_set;      /* work_set array */
+    int                        start_file;     /* index into work_set array */
+    int                        file;           /* index into work_set array */
+
+    int                        nworkfiles;     /* # files in work_set */
+    int                        group_cnt;      /* # file groups in work_set */
+    int                        group_size;     /* size of each group in work_set */
+    int                        group;          /* group index with work_set */
+    int                        offset;         /* file index within group */
+
+    int                        value;          /* distribution function value */
+    int                        previous;       /* binary search for value */
+    int                        low;            /* binary search for value */
+    int                        high;           /* binary search for value */
+
+    int                        found_file = 0; /* count */
+    int                        best_delta = 0;
+    static int         op_num = 0;
+    long               rand_int;
+    int                        max_range;
+
+    op_num++;
+
+    /*
+     * if the more than one type of file will do, choose one.
+     * Note: this code assumes specific values and order for
+     * the entries in sfs_file_enum_type.
+     */
+    switch (file_type) {
+
+       case Sfs_regular:
+           file_type = (int) (sfs_random() % 2);
+           break;
+
+       case Sfs_non_dir:
+           file_type = (int) (sfs_random() % 3);
+           break;
+
+       case Sfs_any_file:
+           file_type = (int) (sfs_random() % 4);
+           break;
+
+       default:
+           break;
+
+    } /* end switch on file type */
+
+    /* get the file type arrays */
+    switch (file_type) {
+
+       case Sfs_io_file:
+           files = Io_files;
+           work_set = &Io_working_set;
+           nworkfiles = Num_working_io_files;
+           break;
+
+       case Sfs_non_io_file:
+           files = Non_io_files;
+           work_set = &Non_io_working_set;
+           nworkfiles = Num_working_non_io_files;
+           break;
+
+       case Sfs_symlink:
+           files = Symlinks;
+           work_set = &Symlink_working_set;
+           nworkfiles = Num_working_symlinks;
+           break;
+
+       case Sfs_dir:
+           files = Dirs;
+           work_set = &Dir_working_set;
+           nworkfiles = Num_working_dirs;
+           break;
+
+       default:
+           (void) fprintf(stderr, "%s: invalid file type\n", sfs_Myname);
+           (void) kill(0, SIGINT);
+           exit(174);
+    } /* end switch on file type */
+
+    /*
+     * Pick the access group.
+     *
+     * Each access group consists of those files in the working set
+     * (numbered according to the file's index in the array) that
+     * have the same value modulo the number of groups.  For example,
+     * a working set of 13 files with 3 groups is organized as
+     *         group   files
+     *         -----   -----------------
+     *           0     0,  3,  6,  9, 12       ie, == 0 mod 3
+     *           1     1,  4,  7, 10           ie, == 1 mod 3
+     *           2     2,  5,  8, 11           ie, == 2 mod 3
+     *
+     * Generate a random number mod the maximum range value of the working set.
+     * and then binary search the first group_cnt entries in the working set
+     * to find the group whose range contains the random number.
+     * (this implements the file access distribution function)
+     */
+    max_range = work_set->max_range;
+    rand_int = (long) sfs_random();
+
+    while ((rand_int / max_range) >= (_M_MODULUS / max_range)) {
+      /*
+       * for large values of max_range, modulo doesn't provide a uniform
+       * distribution unless we exclude these values ...
+       */
+      rand_int = (long) sfs_random();
+    }      
+    value = rand_int % max_range;
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "randfh: size=%d cnt=%d max=%d val=%3d\n",
+                           work_set->access_group_size,
+                           work_set->access_group_cnt,
+                           work_set->max_range, value);
+       (void) fflush(stderr);
+    }
+
+    previous = -1;
+    for (low = 0, high = work_set->access_group_cnt-1, group = (low + high)/2;;
+        previous = group, group = (low + high)/2) {
+
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr,
+                           "PICK GROUP low=%d hi=%d grp=%d range=%d val=%d\n",
+                           low, high, group, work_set->entries[group].range,
+                           value);
+           (void) fflush(stderr);
+       }
+
+       if (previous == group)
+           break;
+       if (work_set->entries[group].range == value)
+           break;
+       if (work_set->entries[group].range > value) {
+           if (group == 0)
+               break;
+           if (work_set->entries[group-1].range < value)
+               break;
+           else
+               high = group - 1;
+       } else if (work_set->entries[group].range < value) {
+           if (work_set->entries[group+1].range > value) {
+               group++;
+               break;
+           } else
+               low = group + 1;
+       }
+    }
+
+    /*
+     * Pick a file within the group to operate on.
+     * Since (working_set_size / group_size) may have a remainder,
+     * groups may have either group_size or (group_size+1) files.
+     */
+    group_cnt = work_set->access_group_cnt;
+    group_size = work_set->access_group_size;
+    if (group < (nworkfiles - ((nworkfiles / group_cnt) * group_cnt)))
+       group_size += 1;
+
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "Selected group = %d\n", group);
+       (void) fflush(stderr);
+    }
+    /*
+     * Beginning with a random starting point in the group,
+     * search for a file that is eligible for this operation.
+     *           index is an index into the files in the group.
+     *           file and start_file are indices into the working set array.
+     */
+    if (DEBUG_CHILD_OPS) {
+       (void) fprintf(stderr, "group_size = %d\n", group_size);
+       (void) fflush(stderr);
+    }
+
+    offset = (int) (sfs_random() % group_size);
+    start_file = group + (offset * group_cnt);
+    file = start_file;
+    do {
+       int f_size;
+       int delta;
+
+       fh = work_set->entries[file].index;
+
+       if (DEBUG_CHILD_OPS) {
+           (void) fprintf(stderr, "PICK FILE op= %d file=%d fh=%d\n",
+                               opnum, file, fh);
+           (void) fprintf(stderr, "fh_state = %d file_state= %d\n",
+                               files[fh].state, file_state);
+           (void) fflush(stderr);
+       }
+
+       /* look for a file that has the right state attribute */
+       if (files[fh].state == file_state) {
+           f_size = fh_size(&files[fh]);
+
+           /*
+            * for read and write ops and setattr truncates,
+            * the file must be large enough to do the xfer or truncate.
+            */
+           if ((opnum == READ) || (opnum == WRITE && !append_flag) ||
+                                                               trunc_flag) {
+
+               /*
+                * If the request is a read and the transfer size is
+                * less than or equal to be block size, grab the first
+                * file that is less than or equal in size.  Should never
+                * see a transfer size less than block size as it will
+                * be rounded up for the request.  This allows small files
+                * to be read.
+                */
+               if (opnum == READ && xfer_size <= Bytes_per_block) {
+                   if (f_size <= Bytes_per_block) {
+                       found_fh = fh;
+                       break;
+                   }
+               }
+/* #define FIRST_FIT */
+#define BEST_FIT
+#ifdef FIRST_FIT
+               if (f_size >= xfer_size) {
+                   found_fh = fh;
+                   break;
+               }
+#endif
+#ifdef BEST_FIT
+               if (DEBUG_CHILD_FIT) {
+                   (void) fprintf(stderr,
+"%s: %8d: xfer_size %d f_size %d best_delta %d found %d\n",
+sfs_Myname, op_num, xfer_size, f_size, best_delta, found_file);
+                   (void) fflush(stderr);
+               }
+
+               /*
+                * If we find an good enough match we should use it.
+                * Define good enough to be xfer_size <= X < xfer_size + 8K
+                * If not we continue to search for the best fit within
+                * a fixed distance 8.
+                */
+               if (f_size >= xfer_size) {
+                   if (f_size < (xfer_size + 8 * 1024)) {
+                       found_fh = fh;
+                       break;
+                   }
+
+                   found_file++;
+                   delta = f_size - xfer_size;
+
+                   if (found_fh == -1) {
+                       best_delta = delta;
+                       found_fh = fh;
+                       /* break; Removed as per Robinson */
+                   }
+
+                   if (delta < best_delta) {
+                       found_fh = fh;
+                       best_delta = delta;
+                   }
+
+                   if (found_file >= 8) {
+                       break;
+                   }
+               }
+#endif
+           } else {
+               /* for non-i/o ops, only requirement is proper file state */
+               found_fh = fh;
+               break;
+           }
+       }
+       offset = (offset + 1) % group_size;
+       file = group + (offset * group_cnt);
+    } while (file != start_file);
+
+    if (found_fh == -1) {
+       /* didn't find a file for this operation */
+       if (DEBUG_CHILD_FIT) {
+           if (opnum == READ || (opnum == WRITE && !append_flag) ||
+               opnum == SETATTR) {
+               (void) fprintf(stderr, "%s: no file for %d byte %d op\n",
+                              sfs_Myname, xfer_size, opnum);
+           } else {
+               (void) fprintf(stderr, "%s: no file for %d op\n",
+                              sfs_Myname, opnum);
+           }
+           (void) fflush(stderr);
+           return((sfs_fh_type *) -1);
+       }
+       return((sfs_fh_type *) NULL);
+    }
+    /* found it */
+    files[found_fh].use_cnt++;
+    return(&files[found_fh]);
+} /* randfh */
+
+/*
+ * ------------------------ Miscellaneous Subroutines  -----------------------
+ */
+
+/*
+ * check to make sure that we have both read and write permissions
+ * for this file or directory given in 'statb'.
+ * return: 0 == ok, -1 == bad
+ */
+int
+check_access(
+    struct stat                *statb)
+{
+    /* check user */
+    if (statb->st_uid == Real_uid) {
+       if ((statb->st_mode & 0400) && (statb->st_mode & 0200)) {
+           return(0);
+       } else {
+           return(-1);
+       }
+    }
+
+    /* check group */
+    if (statb->st_gid == Cur_gid) {
+       if ((statb->st_mode & 040) && (statb->st_mode & 020)) {
+               return(0);
+           } else {
+               return(-1);
+           }
+    }
+
+    /* check other */
+    if ((statb->st_mode & 04) && (statb->st_mode & 02)) {
+       return(0);
+    } else {
+       return(-1);
+    }
+
+} /* check_access */
+
+/*
+ * check to make sure that we have both read and write permissions
+ * for this file or directory given in the file attributes.
+ * return: 0 == ok, -1 == bad
+ */
+int
+check_fh_access(sfs_fh_type *file_ptr)
+{
+    /* check user */
+    if (fh_uid(file_ptr) == Real_uid) {
+       if ((fh_mode(file_ptr) & 0400) && (fh_mode(file_ptr) & 0200)) {
+           return(0);
+       } else {
+           return(-1);
+       }
+    }
+
+    /* check group */
+    if (fh_gid(file_ptr) == Cur_gid) {
+       if ((fh_mode(file_ptr) & 040) && (fh_mode(file_ptr) & 020)) {
+               return(0);
+           } else {
+               return(-1);
+           }
+    }
+
+    /* check other */
+    if ((fh_mode(file_ptr) & 04) && (fh_mode(file_ptr) & 02)) {
+       return(0);
+    } else {
+       return(-1);
+    }
+}
+
+static int last_bad_calls = 0;
+
+/*
+ * Adjust the sleep time per call based on a number of global variables,
+ */
+static void
+check_call_rate()
+{
+    int         call_target_per_period; /* target calls for each period */
+    int         req_target_per_period;  /* target reqs for each period */
+    int         call_target_this_test;  /* target calls for test so far */
+    int         req_target_this_test;   /* target reqs for test so far */
+    int         msec_this_period;       /* actual length of this period */
+    int         msec_this_test;         /* actual length of test so far */
+    uint_t     current_msec;           /* current time in msecs */
+    int         old_target_sleep_mspc;
+    struct ladtime elapsed_time;       /* Current_time - Start_time */
+
+    int         reqs_needed_next_period;/* req target for the next period */
+    float       mspc;                   /* target msec per call, with/sleep */
+    float       work_mspc;              /* actual msec worked / call */
+
+
+    if (Child_num == -1)
+       /* I'm the parent, ignore the signal */
+       return;
+
+    /* update the test so far totals */
+    Calls_this_test += Calls_this_period;
+    Reqs_this_test += Reqs_this_period;
+    Sleep_msec_this_test += Sleep_msec_this_period;
+
+    /* compute per period targets */
+    call_target_per_period = (int) (Child_call_load *
+                            ((float) Msec_per_period / (float) 1000));
+    req_target_per_period = (int) (Child_req_load *
+                           ((float) Msec_per_period / (float) 1000));
+
+    /*
+     * The child() routine retrieved the Cur_time when deciding to call us.
+     * Use Cur_time to compute the elapsed time since the last checkpoint
+     * and the current checkpoint time (ie, elapsed time since test began)
+     */
+    /* sfs_gettime(&Cur_time); */
+    elapsed_time.sec = Cur_time.sec;
+    elapsed_time.usec = Cur_time.usec;
+    SUBTIME(elapsed_time, Starttime);
+
+    msec_this_test = (elapsed_time.sec * 1000) + (elapsed_time.usec / 1000);
+    current_msec = (Cur_time.sec * 1000) + (Cur_time.usec / 1000);
+    msec_this_period = current_msec - Previous_chkpnt_msec;
+
+    if (msec_this_test < Sleep_msec_this_test) {
+       if (DEBUG_CHILD_XPOINT) {
+           (void) fprintf(stderr,
+                        "Accum. sleep time %d is msecs ahead of wall clock\n",
+                                Sleep_msec_this_test - msec_this_test);
+           (void) fflush(stderr);
+       }
+       Sleep_msec_this_test = msec_this_test;
+    }
+
+    /* compute targets for test so far */
+    call_target_this_test = (int) ((Child_call_load * (float) msec_this_test)
+                                  / (float) 1000);
+    req_target_this_test = (int) ((Child_req_load * (float) msec_this_test)
+                                  / (float) 1000);
+
+    /* save the old sleep rate */
+    old_target_sleep_mspc = Target_sleep_mspc;
+
+    /* Compute how long each request has taken on average. */
+    if (Reqs_this_test != 0)
+       work_mspc = ((float) (msec_this_test - Sleep_msec_this_test))
+                    / (float) Reqs_this_test;
+    else
+       work_mspc = (1000.0 / (float) Child_req_load) / 2.0;
+
+    /*
+     * Compute the number of reqs needed in the next period
+     * in order to just meet the reqstarget for the test when that period ends.
+     * (Try to make up the entire shortage or overage in the next period.)
+     * Beware that we might not need to make any reqs next period.
+     */
+    reqs_needed_next_period = (req_target_this_test - Reqs_this_test)
+                             + req_target_per_period;
+
+    if (reqs_needed_next_period <= 0) {
+       /* if no reqs are needed, set the sleep time to the whole period */
+       mspc = 0.0;
+       Target_sleep_mspc = Msec_per_period;
+    } else {
+       /* decide how much time is available for each request */
+       mspc = (float) (Msec_per_period) / (float) (reqs_needed_next_period);
+       Target_sleep_mspc = (int) (mspc - work_mspc);
+    }
+
+    /* Don't increase the target_sleep_mspc by much more than a factor of two,
+        because doing so can lead to violent oscillations. */
+    if (Target_sleep_mspc > 2*(old_target_sleep_mspc + 5)) {
+       Target_sleep_mspc = 2*(old_target_sleep_mspc + 5);
+    }    
+
+    if (Target_sleep_mspc >= Msec_per_period) {
+        Target_sleep_mspc = Msec_per_period;
+       if (DEBUG_CHILD_XPOINT) {
+           (void) fprintf(stderr,
+    "Child %d: 0 call, rqnd %d mspc %3.2f wmspc %3.2f time %d slp %d reqs %d\n",
+                   Child_num, reqs_needed_next_period, mspc, work_mspc,
+                   msec_this_test, Sleep_msec_this_test, Reqs_this_test);
+           (void) fflush(stderr);
+       }
+        if (Measurement_in_progress) {
+           (void) fprintf(stderr,
+               "Child %d:  0 calls during measurement interval\n",Child_num);
+           (void) fprintf(stderr,
+                    "Child %d:  probably unstable, try more processes.\n",Child_num);
+           (void) generic_kill(0, SIGINT);
+           (void) fflush(stderr);
+           exit(188);
+         }
+    }
+    if (Target_sleep_mspc <= 0) {
+        Target_sleep_mspc = 0;
+        if (DEBUG_CHILD_XPOINT) {
+               (void) fprintf(stderr,
+    "Child %d: 0 slp, rqnd %d mspc %3.2f wmspc %3.2f time %d slp %d reqs %d\n",
+                       Child_num, reqs_needed_next_period, mspc, work_mspc,
+                       msec_this_test, Sleep_msec_this_test, Reqs_this_test);
+               (void) fflush(stderr);
+        }
+    }
+
+    if (DEBUG_CHILD_XPOINT) {
+       (void) fprintf(stderr, "Child %d\n%s", Child_num,
+       "        msec_prd  calls_prd reqs_prd calls_tot req_tot    mspc_req\n");
+       (void) fprintf(stderr, "target: %8d %9d %8d %9d %8d    %6.2f\n",
+                       Msec_per_period,
+                       call_target_per_period, req_target_per_period,
+                       call_target_this_test, req_target_this_test,
+                       1000.0 / (float) req_target_per_period);
+       (void) fprintf(stderr, "actual: %8d %9d %8d %9d %8d  ->%6.2f\n",
+                       msec_this_period,
+                       Calls_this_period, Reqs_this_period,
+                       Calls_this_test, Reqs_this_test,
+                       mspc);
+       (void) fprintf(stderr,
+                       "        old_sleep_mspc  %5d   new_sleep_mspc  %5d\n\n",
+                       old_target_sleep_mspc, Target_sleep_mspc);
+    }
+
+    /*
+     * check for too many failed RPC calls
+     * and print a warning if there are too many.
+     */
+    if (((Ops[TOTAL].results.bad_calls - last_bad_calls) > 100) ||
+       ((Ops[TOTAL].results.good_calls > 300) &&
+        ((Ops[TOTAL].results.bad_calls - last_bad_calls) >
+                                       Ops[TOTAL].results.good_calls/50))) {
+       (void) fprintf(stderr,
+                       "%s: too many failed RPC calls - %d good %d bad\n",
+                       sfs_Myname, Ops[TOTAL].results.good_calls,
+                       Ops[TOTAL].results.bad_calls);
+       last_bad_calls = Ops[TOTAL].results.bad_calls;
+    }
+
+    /* reset the period counters */
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Previous_chkpnt_msec = current_msec;
+
+} /* check_call_rate */
+
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_chd.work b/TBBT/trace_play/sfs_c_chd.work
new file mode 100644 (file)
index 0000000..195beb0
--- /dev/null
@@ -0,0 +1,3815 @@
+/* Try to change thread scheduling and uses three threads */
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------- sfs_c_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static int read_trace(void);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+void adjust_play_window (int flag, int * poll_timeout_arg);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern inline fh_map_t * lookup_fh (char * trace_fh );
+static void finish_request (int biod_index, int dep_index, int status, int dep_flag);
+static inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+static inline char * find_lead_trace_fh(int proc, char * line);
+static inline char * find_reply_trace_fh (char * line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/* as long as the inital value is different, then it's OK */
+int recv_num = 0;
+int timeout_num = 0;
+int send_num = 0;
+int exit_flag = 0;
+int async_rpc_sem;
+int no_progress_flag = 0;
+int num_out_reqs_statistics[MAX_OUTSTANDING_REQ+1];
+int num_out_reqs_statistics_at_timeout[MAX_OUTSTANDING_REQ+1];
+
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                       22, 19};
+void print_usage(int pos, int argc, char ** argv)
+{
+       int i;
+       printf("sfs3 hostname:mount_dir trace_file|stdin fh_map_file play_scale warmup_time(in seconds) \n");
+       printf("sfs3 -pair_trace trace_file\n");
+       printf("sfs3 -pair_write trace_file\n");
+       printf("sfs3 -help\n");
+       printf ("pos %d argc %d", pos, argc);
+       for (i=0; i<argc; i++) {
+               printf(" %s", argv[i]);
+       } 
+       printf ("\n");
+       exit;
+}
+
+void print_cyclic_buffers ()
+{
+       CYCLIC_PRINT(memory_trace_index);
+       CYCLIC_PRINT(dep_tab_index);
+       CYCLIC_PRINT(dep_window_index);
+}
+
+void add_to_dep_tab(int i)
+{
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       dep_tab_t * ent;
+
+    trace_fh = strstr (memory_trace[i].line, "fh");
+    if (!trace_fh)
+       printf ("memory_trace[%d].line %s\n", i, memory_trace[i].line);
+    RFS_ASSERT (trace_fh);
+    trace_fh += 3;
+    fh_map_entry = lookup_fh (trace_fh);
+    if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+        req_num_with_discard_fh ++;
+               return;
+       }
+    if (fh_map_entry)
+        req_num_with_init_fh ++;
+    else
+        req_num_with_new_fh ++;
+                                                                                                                              
+       RFS_ASSERT (!CYCLIC_FULL(dep_tab_index));
+       ent = &(dep_tab[dep_tab_index.head]);
+
+    ent->disk_index = memory_trace[i].disk_index;
+       ent->memory_index = i;
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+    ent->trace_status = memory_trace[i].trace_status;
+    ent->reply_trace_fh = memory_trace[i].reply_trace_fh;
+#endif
+    ent->line = memory_trace[i].line;
+    init_dep_tab_entry(dep_tab_index.head);
+
+    if (rfs_debug && (i%100000)==0)
+       printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_index.head, ent->disk_index, i, memory_trace[i].disk_index);
+    CYCLIC_MOVE_HEAD(memory_trace_index);
+    CYCLIC_MOVE_HEAD(dep_tab_index);
+}
+
+void init_profile_variables ()
+{
+       init_profile ("total_profile", &total_profile);
+       init_profile ("execute_next_request_profile", &execute_next_request_profile);
+       init_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       init_profile ("invalid_get_nextop_profile",&invalid_get_nextop_profile);
+       init_profile ("prepare_argument_profile", &prepare_argument_profile);
+       init_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       init_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       init_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       init_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       init_profile ("decode_reply_profile", &decode_reply_profile);
+       init_profile ("check_reply_profile", &check_reply_profile);
+       init_profile ("add_create_object_profile", &add_create_object_profile);
+       init_profile ("check_timeout_profile", &check_timeout_profile);
+       init_profile ("adjust_play_window_profile",&adjust_play_window_profile);
+       init_profile ("fgets_profile",&fgets_profile);
+       init_profile ("read_line_profile",&read_line_profile);
+       init_profile ("read_trace_profile",&read_trace_profile);
+}
+
+static char trace_file[256]="anon-lair62-011130-1200.txt";
+int print_memory_usage()
+{
+       printf("size of fh_map_t %d size of fh_map %d\n", sizeof(fh_map_t), sizeof(fh_map));
+       printf("sizeof dep_tab_t %d sizeof dep_tab %d\n", sizeof(dep_tab_t), sizeof(dep_tab));
+       printf("size of memory_trace_ent_t %d sizeof memory_trace %d\n", sizeof(memory_trace_ent_t), sizeof(memory_trace));
+       printf("size of CREATE3args %d\n", sizeof( CREATE3args));
+       printf("size of MKDIR3args %d\n", sizeof( MKDIR3args));
+       printf("size of READ3args %d\n", sizeof( READ3args));
+       printf("size of WRITE3args %d\n", sizeof( WRITE3args));
+       printf("size of RENAME3args %d\n", sizeof( RENAME3args));
+       printf("size of GETATTR3args %d\n", sizeof( GETATTR3args));
+       printf("size of SETATTR3args %d\n", sizeof( SETATTR3args));
+       printf("size of LINK3args %d\n", sizeof( LINK3args));
+       printf("size of SYMLINK3args %d\n", sizeof( SYMLINK3args));
+       printf("size of MKNOD3args %d\n", sizeof( MKNOD3args));
+       printf("size of RMDIR3args %d\n", sizeof( RMDIR3args));
+       printf("size of REMOVE3args %d\n", sizeof( REMOVE3args));
+       printf("size of LOOKUP3args %d\n", sizeof( LOOKUP3args));
+       printf("size of READDIR3args %d\n", sizeof( READDIR3args));
+       printf("size of READDIRPLUS3args %d\n", sizeof( READDIRPLUS3args));
+       printf("size of FSSTAT3args %d\n", sizeof( FSSTAT3args));
+       printf("size of FSINFO3args %d\n", sizeof( FSINFO3args));
+       printf("size of COMMIT3args %d\n", sizeof( COMMIT3args));
+       printf("size of ACCESS3args %d\n", sizeof( ACCESS3args));
+       printf("size of READLINK3args %d\n", sizeof( READLINK3args));
+
+
+}
+
+void recv_thread()
+{
+       int last_print_time = -1;
+       int busy_flag;
+
+       while (send_num ==0) {
+               usleep(1000);
+       }
+
+       //while (!CYCLIC_EMPTY(dep_tab_index)) {
+       while (!exit_flag) {
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       static int recv_num_before_10_seconds = 0;
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, "<<<<< recv_thread recv_num %d time %d num_out_reqs %d \n", recv_num, total_profile.in.tv_sec, num_out_reqs);
+                       if (recv_num == recv_num_before_10_seconds) {
+                               no_progress_flag = 1;
+                               RFS_ASSERT (0);
+                       } else 
+                               recv_num_before_10_seconds = recv_num;
+               }
+               //start_profile (&check_timeout_profile);
+               check_timeout();
+               //end_profile (&check_timeout_profile);
+
+               pthread_yield();
+               //usleep(1000);
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1) {
+                       busy_flag = BUSY;
+               }
+#endif
+               end_profile (&receive_next_reply_profile);
+       }
+       printf ("<<<< recv thread EXIT\n");
+       exit_flag = 2;
+}
+
+int io_thread ()
+{
+/* number of seconds the I/O thread pauses after each time trying to read the requests */
+#define IO_THREAD_PAUSE_TIME 1
+
+       int i;
+       int j = 0;
+
+       disk_io_status = read_trace ();
+       while (disk_io_status == TRACE_BUF_FULL) {
+
+               usleep (10000);
+        if ((j++%1000)==0) {
+                printf("&&&&&&&&&& io thread, sleep %d seconds\n", j/100);
+        }
+
+               disk_io_status = read_trace ();
+               //printf ("io_thread, after read_trace, disk_index %d\n", disk_index);
+
+#ifdef SEQUEN_READ
+               for (i=0; i<SEQUEN_READ_NUM; i++) {
+                       add_to_dep_tab(CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size));
+               }
+#endif
+               //printf ("***************** IO THREAD SLEEP 1 s\n");
+               //print_cyclic_buffers();
+               //pthread_yield();
+       }
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       printf("io_thread EXIT\n");
+}
+
+int execute_thread()
+{
+       int i;
+       struct timeval playstart_time, playend_time;
+
+       sleep (10);             /* first let io_thread to run for a while */
+       printf ("trace_play\n");
+
+       gettimeofday(&playstart_time, NULL);
+
+       init_time_offset();
+       trace_play ();
+
+       gettimeofday(&playend_time, NULL);
+
+       {
+               int usec, sec;
+               sec = playend_time.tv_sec - playstart_time.tv_sec;
+               usec = sec * 1000000 + (playend_time.tv_usec - playstart_time.tv_usec);
+               sec = usec / 1000000;
+               usec = usec % 1000000;
+               printf("Total play time: %d sec %d usec\n", sec, usec);
+               if (sec > WARMUP_TIME)
+                       print_result();
+               else
+                       printf ("the trace play time %d is less than WARMUP_TIME %d, no statistical results\n");
+       }
+#ifdef RECV_THREAD
+       exit_flag = 1;
+       while (exit_flag == 1) {
+               usleep (1000);
+       }
+#endif
+
+    clnt_destroy(NFS_client);
+    biod_term();
+}
+
+int init_thread ()
+{
+       pthread_attr_t  attr;
+       int arg;
+       int ret = 0;
+       pthread_t io_thread_var;
+#ifdef RECV_THREAD
+       pthread_t recv_thread_var;
+#endif
+       pthread_t execute_thread_var;
+
+       ret = pthread_attr_init (&attr);
+       if (ret!=0) {
+               perror("pthread_attr_init attr");
+               return ret;
+       }
+#ifdef IO_THREAD
+       ret = pthread_create (&(io_thread_var), &attr, &io_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+#ifdef RECV_THREAD
+       ret = pthread_create (&(recv_thread_var), &attr, &recv_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("recv_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+/*
+       ret = pthread_create (&(execute_thread_var), &attr, &execute_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+*/
+}
+
+void init_buffers()
+{
+       CYCLIC_INIT("memory_trace_index",memory_trace_index,MAX_MEMORY_TRACE_LINES);
+       CYCLIC_INIT("dep_tab_index     ",dep_tab_index,DEP_TAB_SIZE);
+       CYCLIC_INIT("dep_window_index  ",dep_window_index,DEP_TAB_SIZE);
+}
+
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       int i;
+       struct timeval in={1000000, 100};
+       
+       init_profile_variables();
+       if ((argc==1) || (argc==2 && !strcmp(argv[1],"-help"))) {
+               print_usage(0, argc, argv);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_write")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_write(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_trace")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_trace(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_aging")) {
+               if (argc!=3) {
+                       print_usage(3, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               check_aging (trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_statistics")) {
+               if (argc!=3) {
+                       print_usage(1, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               memset(fh_htable, 0, sizeof (fh_htable));
+               check_statistics (trace_file);
+               exit(0);
+       }
+
+       if (argc!=6) {
+               print_usage(2, argc, argv);
+               exit(0);
+       }
+
+       PLAY_SCALE = atoi (argv[4]);
+       RFS_ASSERT (PLAY_SCALE >=1 && PLAY_SCALE <=10000);
+
+       WARMUP_TIME = atoi (argv[5]);
+       RFS_ASSERT (WARMUP_TIME >=0 && WARMUP_TIME <=1000);
+       
+       print_memory_usage();
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_semaphores();
+       init_file_system ();
+       init_signal();
+       init_play (argv[1]);
+       //init_play ("capella:/p5/RFSFS");
+       init_fh_map();
+       read_fh_map (argv[3]);
+       //read_fh_map ("fh-path-map-play");
+       strcpy(trace_file, argv[2]);
+
+/* If ordered by TIMESTAMP,
+ * memory_trace_index.tail <= dep_tab_index.tail < dep_window_max <=
+ * dep_tab_index.head <= memory_trace_index.head
+ */
+
+       init_global_variables();
+       init_buffers();
+       init_thread();
+       pthread_yield();
+       execute_thread();
+}
+
+int init_global_variables()
+{
+       memset (num_out_reqs_statistics, 0, sizeof(num_out_reqs_statistics));
+       memset (num_out_reqs_statistics_at_timeout, 0, sizeof(num_out_reqs_statistics_at_timeout));
+}
+
+int init_semaphores()
+{
+       async_rpc_sem = dest_and_init_sem (ASYNC_RPC_SEM_KEY, 1, "async_rpc_sem");
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+}
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+void inline format_line (char * line_before, char * line)
+{
+       char * pv = line_before;
+       char * pl = line;
+       char * p;
+       int i;
+       
+       //printf("format_line before %s\n", line_before);
+       p = strstr (pv, "fh");
+       while (p!=NULL) {
+               while (pv<=p)
+                       *pl++ = *pv++;
+               *pl++ = *pv++;
+               if (*pv==2) {
+                       *pl++ = *pv++;
+               }
+               *pl++ = *pv++;
+               i = 0;
+               while (*pv !=' ') {
+                       RFS_ASSERT ((*pv >='0' && *pv <='9') || (*pv >='a' && *pv<='f'));
+                       *pl++ = *pv++;
+                       i++;
+               }
+               RFS_ASSERT ((i==48) || (i==40) || (i==24));
+               while (i<48) {
+                       *pl++ = '0';
+                       i++;
+               }
+               p = strstr (pv, "fh");
+       }
+       while ((*pv)!=NULL) {
+               *pl++ = *pv++;
+       }
+       //printf("format_line after %s\n", line);
+}
+
+char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+       static int varfh_flag = 0;
+#define READ_LINE_BUF_SIZE (MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR+2)
+#define SAFE_BYTES 1000
+#define READ_LINE_LENGTH (MAX_TRACE_LINE_LENGTH+SAFE_BYTES)
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       char varfh_line_buf[READ_LINE_LENGTH];
+
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+
+                       if (strstr(trace_file, ".varfh")) {
+                               varfh_flag = 1;
+                       };
+                       if (strstr(trace_file, ".fmt1")) {
+                               TRACE_COMMAND_REPLY_FLAG_POS += 12;
+                               TRACE_VERSION_POS +=12;
+                               TRACE_MSGID_POS +=12;
+                               TRACE_FH_SIZE =48;
+                       }
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (varfh_flag) {
+                               if (!fgets(varfh_line_buf, READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                               format_line (varfh_line_buf, line_buf[i]);
+                       } else {
+                               if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       if (disk_index > start_disk_index+READ_LINE_BUF_SIZE) {
+               printf ("disk_index %d start_disk_index %d READ_LINE_BUF_SIZE %d\n", 
+                       disk_index, start_disk_index, READ_LINE_BUF_SIZE);
+       }
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+/*
+       if (!(strlen(line_buf[i])>80)) {
+               printf ("start %d start_disk_index %d disk_index %d strlen %d line_buf[%d] %s\n", start, start_disk_index, disk_index, strlen(line_buf[i]), i, line_buf[i]);
+               RFS_ASSERT (strlen(line_buf[i])>80);
+       }
+       if (!((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH)))
+               printf ("disk_index %d strlen %d line_buf[%d] %s\n", disk_index, strlen(line_buf[i]), i, line_buf[i]);
+       RFS_ASSERT ((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH));
+*/
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+#define OPS_FLAG_INC 0
+#define OPS_FLAG_PRINT 1
+int read_write_fh_statistics (int flag, char * buf, int timestamp)
+{
+       static FILE * fp = NULL;
+       char * p;
+       char c;
+       if (!fp) {
+               fp = fopen ("read_write_fh.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (buf, "fh");
+               RFS_ASSERT (p);
+               c = p[40+3];
+               p[40+3]=0;
+               fprintf(fp, "%s\n", p+3+24);
+               p[40+3]=c;
+       };
+       if (flag == OPS_FLAG_PRINT) { 
+               int disk_index = (int) buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+int write_statistics(int flag, char * buf, char * reply_buf, int trace_status)
+{
+       static FILE * fp = NULL;
+       int pre_size, size, count;
+       char * p = reply_buf;
+       if (!fp) {
+               fp = fopen ("write.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (p, "pre-size");
+               RFS_ASSERT (p);
+               sscanf (p, "pre-size %x", &pre_size); 
+               p += strlen("pre-size");
+               p = strstr (p, "size");
+               RFS_ASSERT (p);
+               sscanf (p, "size %x", &size); 
+               p = strstr (p, "count");
+               if (!p) 
+                       fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+               RFS_ASSERT (p);
+               sscanf (p, "count %x", &count); 
+               fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+       }
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = (int) buf;
+               int timestamp = (int) reply_buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+void ops_statistics (int ops_flag, int proc, int timestamp)
+{
+       static FILE * fp = NULL;
+       static struct {
+               int count;
+               int count_K;
+               int update_flag;
+               char name[32];
+       } ops[NOPS]={{0, 0, 0, "NULL"},{0, 0, 0, "GETATTR"},{0, 0, 1, "SETATTR"},{0, 0, 0, "ROOT"},
+                                 {0, 0, 0, "LOOKUP"},{0, 0, 0, "READLINK"},{0, 0, 0, "READ"},{0, 0, 1, "WRCACHE"},
+                                 {0, 0, 1, "WRITE"}, {0, 0, 1, "CREATE"},{0, 0, 1, "REMOVE"},{0, 0, 1, "RENAME"},
+                                 {0, 0, 1, "LINK"}, {0, 0, 1, "SYMLINK"},{0, 0, 1, "MKDIR"},{0, 0, 1, "RMDIR"},
+                                 {0, 0, 0, "READDIR"},{0, 0, 0, "FSSTAT"},{0, 0, 0, "ACCESS"},{0, 0, 0, "COMMIT"},
+                                 {0, 0, 0, "FSINFO"},{0, 0, 1, "MKNOD"}, {0, 0, 0, "PATHCONF"}, {0, 0, 0, "READDIRPLUS"}};
+
+       if (ops_flag == OPS_FLAG_INC) {
+               RFS_ASSERT (proc>=0 && proc<NOPS);
+               ops[proc].count ++;
+               if (ops[proc].count == 1000) {
+                       ops[proc].count_K ++;
+                       ops[proc].count = 0;
+               }
+       }
+       if (ops_flag == OPS_FLAG_PRINT) {
+               int i;
+               int update_K=0, update=0, total_K=0, total=0;
+               float f1, f2;
+               int disk_index = proc;
+
+               if (!fp) {
+                       fp = fopen ("mix.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               for (i=0; i<NOPS; i++) {
+                       total_K += ops[i].count_K;
+                       total += ops[i].count;
+                       if (ops[i].update_flag) {
+                               update_K += ops[i].count_K;
+                               update += ops[i].count;
+                       }
+               }
+               update_K += update/1000;
+               update = update%1000;
+               total_K += total/1000;
+               total = total%1000;
+
+               f1 = total_K;
+               f1 = f1*1000+total;
+               for (i=0; i<NOPS; i++) {
+                       f2 = ops[i].count_K;
+                       f2 = f2*1000+ops[i].count;
+                       fprintf (fp, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);  
+                       fprintf (stderr, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);      
+               }
+               f2 = update_K;
+               f2 = f2*1000+update;
+               fprintf (fp, "       total %8d,%03d\n", total_K, total);
+               fprintf (stderr, "       total %8d,%03d\n", total_K, total);
+               fprintf (fp, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);   
+               fprintf (stderr, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);       
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+               fprintf(stderr, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+
+void truncate_statistics (int flag, int proc, char * buf, char * reply_buf) 
+{
+#define TRACE_FH_SIZE2 16
+#define BLOCK_SIZE 4096
+       static int no_size_num = 0;
+       static int have_size_num = 0;
+       static int equal_size_num = 0;
+       static int first_size_num = 0;
+       static int truncate_num = 0;
+       static int truncate_size = 0;
+       static int truncate_KB = 0;
+       static int truncate_block_num = 0;
+       static int padding_num = 0;
+       static int padding_KB = 0;
+       static int padding_size = 0;
+       static FILE * fp = NULL;
+       char * p;
+       char * trace_fh;
+       int pre_size, size, count;
+       struct generic_entry * ent;
+
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = proc;
+               int timestamp = (int)buf;
+               if (!fp) {
+                       fp = fopen ("truncate.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               truncate_KB += truncate_size/1000;
+               truncate_size %= 1000;
+               padding_KB += padding_size/1000;
+               padding_size %= 1000;
+               fprintf(fp, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               fprintf(stderr, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               return;
+       }
+
+       p = strstr (&buf[TRACE_MSGID_POS], "fh");
+       RFS_ASSERT (p);
+       p+=3; 
+       trace_fh = p;
+               
+       if (proc==SETATTR) {
+               p = strstr (buf, " size ");
+       } else {
+               RFS_ASSERT (proc==WRITE);
+               p = strstr (reply_buf, " ftype 1 ");
+               RFS_ASSERT (p);
+               p = strstr (p, " size ");
+               RFS_ASSERT (p);
+               if (strstr(p, " ftype 1 ")) {
+                       fprintf (fp, "#### %s%s\n", buf, reply_buf);
+                       fprintf (stderr, "#### %s%s\n", buf, reply_buf);
+               }
+               RFS_ASSERT (!strstr(p, " ftype 1 "));
+       }
+       if (!p) {
+               no_size_num ++;
+               return;
+       }
+       have_size_num ++;
+
+       sscanf (p, " size %x", &size); 
+       if (size <0 || size > 2000000000) {
+               fprintf (fp, "#### size too big %x %s %s\n", size, buf, reply_buf);
+               fprintf (stderr, "#### size too big %x %s %s\n", size, buf, reply_buf);
+       }
+                                                       
+       RFS_ASSERT (size >=0 && size <2000000000);              
+       ent = generic_lookup (trace_fh+24, TRACE_FH_SIZE2, 0, fh_htable, FH_HTABLE_SIZE);
+       if (ent) {
+               if (ent->key3 != size) {
+                       if (proc==SETATTR) {
+                               //printf ("%s\n", buf);
+                               //printf ("size change fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                               if (ent->key3 > size) {
+                                       truncate_num ++;
+                                       truncate_size += ent->key3 - size;
+                                       truncate_block_num += (ent->key3+BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       if (size!=0) {
+                                               //fprintf (stderr, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               //fprintf (fp, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               truncate_block_num -= (size + BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       }
+                                       if (truncate_size > 1000000000) {
+                                               truncate_KB += truncate_size/1000;
+                                               truncate_size %= 1000;
+                                       }
+                               } else {
+                                       padding_num ++; 
+                                       //printf ("%s\n", buf);
+                                       //printf ("padding fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                                       padding_size += size - ent->key3;
+                                       if (padding_size > 1000000000) {
+                                               padding_KB += padding_size/1000;
+                                               padding_size %= 1000;
+                                       }
+                               }
+                       }
+                       ent->key3 = size; 
+               }else 
+                       equal_size_num++;
+       } else {
+               generic_insert(trace_fh+24, TRACE_FH_SIZE2, size, fh_htable, FH_HTABLE_SIZE);
+               first_size_num ++;
+       }
+};
+
+int get_timestamp_usec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       RFS_ASSERT (str[17]==' ');
+       str[17]=0;
+       ret = atoi(&str[11]);
+       RFS_ASSERT (ret >=0 && ret <=999999);
+       return ret;
+}
+
+int get_timestamp_sec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       str[10]=0;
+       ret = atoi(str);
+       RFS_ASSERT (ret >1000000000 && ret <2000000000);
+       return ret;
+}
+
+int check_aging (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               switch (proc) {
+               int off, count, size;
+               char * t;
+               case CREATE: printf("%s\n", "create"); break;
+               case MKDIR: printf("%s\n", "mkdir"); break;
+               case REMOVE: printf("%s\n", "remove"); break;
+               case RMDIR: printf("%s\n", "rmdir"); break;
+               case WRITE: 
+                       t = buf;
+                       t = strstr (t, "off");
+               RFS_ASSERT (t);
+                   t+=4;
+                       sscanf (t, "%x", &off);
+                       RFS_ASSERT (off>=0 && off<0x7FFFFFFF)
+                       t = strstr (t, "count");
+                   RFS_ASSERT (t);
+                       t+=6;
+                       sscanf (t, "%x", &count);
+                       RFS_ASSERT (count <= 32768);
+                       printf("%s off %x count %x\n", "write", off, count); 
+                       //printf("%s count %x\n", "write", count); 
+                       break;
+               case SETATTR: 
+                       t = strstr (buf, " size ");
+                       if (t) {
+                               sscanf (t, " size %x", &size);
+                               printf ("%s size %x\n", "setattr", size);
+                       }
+               }
+               if ((disk_index%10000)==0) {
+                       fprintf(stderr, "%d disk trace passed\n", disk_index);
+               }
+       };
+
+       fprintf(stderr, "%d disk trace parsed\n", disk_index);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, -1);
+}
+
+
+int check_statistics (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+       static int last_timestamp_sec = -1;
+       int timestamp_sec;
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               timestamp_sec = get_timestamp_sec(buf);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               if (proc!= WRITE && proc!=SETATTR && proc!=READ) {
+                       continue;
+               }
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               if (proc==READ || proc==WRITE) 
+                                                       read_write_fh_statistics (OPS_FLAG_INC, buf, 0);
+                                               if (proc == WRITE)
+                                                       write_statistics (OPS_FLAG_INC, buf, reply_buf, trace_status);
+                                               if (proc==WRITE || proc==SETATTR) 
+                                                       truncate_statistics (OPS_FLAG_INC, proc, buf, reply_buf);
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       //printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if *
+               if ((missing_reply_num > memory_trace_size/10) && (missing_reply_num > 100)) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               if (last_timestamp_sec == -1) {
+                       last_timestamp_sec = timestamp_sec;
+               } else if (timestamp_sec - last_timestamp_sec >=3600) {
+                       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+                       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+                       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+                       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+                       last_timestamp_sec = timestamp_sec;
+               }
+/*
+               if ((memory_trace_size%10000)==0) {
+                       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+                       ops_statistics (OPS_FLAG_PRINT, -1);
+                       truncate_statistics (OPS_FLAG_PRINT, -1, NULL, NULL);
+               }
+*/
+       };
+
+       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+}
+
+
+/* This routine output all the requests, together with their replies */
+int pair_trace (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+       FILE * outputfp;
+       char output_file[1024];
+
+       strcpy (output_file, tracefile);
+       strcat (output_file, ".pair");
+       outputfp = fopen (output_file, "w");
+       RFS_ASSERT (outputfp);
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (disk_index == 258)
+                       f();
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+               fprintf (outputfp, "%s\n", buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       fprintf(outputfp, "%s", reply_buf);
+                                       trace_status = find_reply_status(reply_buf);
+                                       if (debug)
+                                               fprintf(stderr, "reply found trace_status %d\n", find_reply_status(reply_buf));
+                                       break;
+                               };
+               }
+               }
+
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       fprintf (stderr, "%s no reply\n", buf);
+                       fprintf(outputfp, "missing_reply\n");
+                       missing_reply_num ++;
+               }
+
+               if (missing_reply_num > memory_trace_size/10 && missing_reply_num >100) {
+                       fprintf (stderr, "missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+
+               memory_trace_size ++;
+
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+/* This routine output all the write requests, together with their replies. It is used for
+ * analysis of write requests: appended bytes, overwrite bytes etc
+ */
+int pair_write (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int pair_write_debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               if (!strstr(buf, "write")) 
+                       continue;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (pair_write_debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               /* store the request to memory */
+               //strcpy (memory_trace[memory_trace_size].line, buf);
+               //memory_trace[memory_trace_size].disk_index = disk_index;
+
+               /* find and store the reply status and reply fhandle to memory */
+               //memory_trace[memory_trace_size].trace_status = NFS3ERR_RFS_MISS;
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (pair_write_debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       int pre_size, size, count;
+                               //memory_trace[memory_trace_size].trace_status = find_reply_status(reply_buf);
+                                       if (pair_write_debug)
+                                               printf("reply found trace_status %d\n", find_reply_status(reply_buf));
+                                               //break;
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               p = strstr (p, "pre-size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "pre-size %x", &pre_size); 
+                                               p += strlen("pre-size");
+                                               p = strstr (p, "size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "size %x", &size); 
+                                               p = strstr (p, "count");
+                                               if (!p) 
+                                                       printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "count %x", &count); 
+                                               printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               break;
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if (missing_reply_num > memory_trace_size/10) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               /*
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               */
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+
+#ifdef notdef
+/* This function is not finished writing */
+int calculate_performance()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+
+typedef struct {
+       struct timeval start;
+       struct timeval stop;
+       int trace_status;
+       int op;
+} trace_performance_ent_t;
+
+       struct timeval req_time;
+       struct timeval reply_time;
+
+       trace_performance_ent_t * ent = NULL;
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+
+               get_timestamp (&ent->req_time, buf);
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               get_timestamp (&ent->reply_time, buf);
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               }
+       }
+}
+#endif
+
+int read_trace ()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+       memory_trace_ent_t * ent=NULL;
+
+       start_profile (&read_trace_profile);
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+       
+               if (rfs_debug)
+                       printf ("disk_index %d %s\n", disk_index, buf);
+
+               if (disk_index==0) {
+                       trace_timestamp1 = get_timestamp_sec (buf);
+                       trace_starttime.sec = get_timestamp_sec (buf);
+                       trace_starttime.usec = get_timestamp_usec (buf);
+                       trace_starttime.esec = 0;
+                       printf ("trace starttime %d %d %d\n", trace_starttime.sec, trace_starttime.usec, trace_starttime.esec);
+               } else
+                       trace_timestamp2 = get_timestamp_sec (buf);
+
+               /* store the request to memory */
+               ent = &(memory_trace[memory_trace_index.head]);
+               strcpy (ent->line, buf);
+               ent->disk_index = disk_index;
+
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               };
+
+               if (ent->trace_status == NFS3ERR_RFS_MISS)
+                       missing_reply_num ++;
+
+               if (MAX_COMMAND_REPLY_DISTANCE > 1) {
+                       if ((missing_reply_num > disk_index/5) && (missing_reply_num > 100)) {
+                               printf ("missing_reply_num %d too high for disk_index %d\n", missing_reply_num, disk_index);
+                               exit (0);
+                       }
+               }
+
+               /* find and store the reply trace fhandle for create-class requests */
+               if (ent->trace_status==NFS3_OK) {
+                       if (strstr(buf, "create") || strstr(buf, "mkdir") 
+                               || (strstr(buf, "symlink") && (buf[TRACE_VERSION_POS]!='2')) 
+                               || strstr(buf, "mknod") ) {
+                               p = find_reply_trace_fh(reply_buf);
+                               if (p==NULL) {
+                                       printf("skip line disk_index %d %s \n", disk_index, buf);
+                                       continue;
+                               }
+                               memcpy(ent->reply_trace_fh, p, TRACE_FH_SIZE);
+                       } else
+                               memset(ent->reply_trace_fh, 0, TRACE_FH_SIZE);
+               }
+
+               add_to_dep_tab(memory_trace_index.head);
+
+               if (((disk_index+1)%20000)==0) {
+                       fprintf(stderr, "%d disk trace parsed \n", disk_index+1);
+               };
+       };
+
+       end_profile (&read_trace_profile);
+       return TRACE_BUF_FULL;
+}
+#else  /* not defined REDUCE_MEMORY_TRACE_SIZE */
+int read_trace ()
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(trace_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, MAX_TRACE_LINE_LENGTH, fp)) {
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+               /* store the request to memory */
+               strcpy (memory_trace[memory_trace_size].line, buf);
+               memory_trace[memory_trace_size].disk_index = disk_index;
+               memory_trace_size ++;
+
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               if ((disk_index%100000)==0)
+                       fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+               disk_index ++;
+       }
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+}
+#endif
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+
+       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index));
+       RFS_ASSERT (memory_trace[memory_trace_index.tail].disk_index <= disk_index);
+       RFS_ASSERT (memory_trace[CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size)].disk_index >=disk_index);
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index = CYCLIC_ADD(memory_index,1,memory_trace_index.size);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index = CYCLIC_MINUS(memory_index,1,memory_trace_index.size);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       if (rfs_debug)
+               printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       if (!(line[TRACE_COMMAND_REPLY_FLAG_POS]=='R')) {
+               printf ("disk_index %d %s\n", disk_index, line);
+       };
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       p = line+TRACE_MSGID_POS+2;     /* at least one letter for msgid and one letter for space */
+       if (strstr(p, "OK"))
+               return NFS3_OK;
+       if (strstr(p, "lookup 2") || strstr(p, "lookup   2"))
+               return 0x2;
+       if (strstr(p, "create d"))
+               return 0xd;
+       if (strstr(p, "setattr 1"))
+               return 0x1;
+       if (strstr(p, "setattr 2712")) /* 10002 NFS3ERR_NOT_SYNC */
+               return 0x2712;
+       if (strstr(p, "lookup d"))
+               return 0xd;
+       if (strstr(p, "read d"))
+               return 0xd;
+       if (strstr(p, "write d"))
+               return 0xd;
+       if (strstr(p, "write 46"))
+               return 0x46;
+       if (strstr(p, "getattr 46"))
+               return 0x46;
+       if (strstr(p, "mkdir d"))
+               return 0xd;
+       printf ("line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       printf ("!!!!!!!!!!!!!!!!!!!!!!!!\n");
+       fprintf (stderr, "line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       fprintf (stderr, "!!!!!!!!!!!!!!!!!!!!!!!!\n");
+}
+
+inline int find_reply_status_old (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p) {
+               printf ("disk_index %d find_reply_trace_fh line %s\n", disk_index, line);
+               return NULL;
+       } else
+               return p+6;
+}
+
+#ifndef NO_DEPENDENCY_TABLE
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+#endif
+
+inline int is_play_candidate (int dep_index)
+{
+       int proc = dep_tab[dep_index].proc;
+       int status = dep_tab[dep_index].status;
+       int trace_status = dep_tab[dep_index].trace_status;
+
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       /* for a failed create in trace, trace_replay just ignore many time the trace create fail
+        * due to access control, but trace_play will success because our access control
+        * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+        */
+       if ((proc==CREATE || proc==MKDIR) && (trace_status!=NFS3_OK) && (status!=NFS3ERR_RFS_MISS)) {
+               if (dependency_debug)
+                       printf ("disk[%d] ignore failed create/mkdir in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               failed_create_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_OTHER_FAILED_COMMAND
+       if (((trace_status == NFS3ERR_ACCES) && (proc==READ || proc==WRITE || proc==LOOKUP)) || 
+           ((trace_status == NFS3ERR_PERM) && (proc==SETATTR))                                                                         ){
+               if (dependency_debug)
+                       printf ("disk[%d] ignore other failed command in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               
+               failed_other_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK) ) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+/* This is actually take care in get_nextop by checking fh_map error when dep_index==min_dep_index */
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+/*
+       if ((    ((dep_tab[dep_index].disk_index==262213) || (dep_tab[dep_index].disk_index==214402))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1100.txt")) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+*/
+       if ((    ((dep_tab[dep_index].disk_index==423727) || (0))
+                 && !(strncmp(trace_file, "anon-lair62-011130-1500.txt", strlen("anon-lair62-011130-1500.txt"))) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+       /* this line is about the mkdir 116d9d originally in anon-lair62-011130-1400.txt */
+       if (!strncmp(dep_tab[dep_index].line, "1007147245.194201", strlen("1007147245.194201"))) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_FSSTAT_COMMAND
+       /* the file handle used in this command is not processed properly by pre-processing */
+       if (proc==FSSTAT) {
+               char * trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+               fh_map_t * fh = lookup_fh (trace_fh);
+               if (!fh) {
+                       skipped_fsstat_command_num++;
+                       return FALSE;
+               }
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+static inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+#define INIT_MIN_WAIT_VALUE -999
+       static int min_wait_fhandle_dep_index = INIT_MIN_WAIT_VALUE;
+       int proc;
+       int flag;
+
+       if (min_wait_fhandle_dep_index == -999)
+               min_wait_fhandle_dep_index = dep_window_index.head;
+
+       for (i=0; i<CYCLIC_NUM(dep_window_index); i++) {
+               dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (CYCLIC_LESS(dep_tab_index,dep_index,min_wait_fhandle_dep_index)) 
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       if (dep_index==dep_window_index.tail) {
+                                               if (!profile_debug) 
+                                                       printf ("fh_path_map error disk[%d] state DEP_FLAG_WAIT_FHANDLE to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                                               fh_path_map_err_num ++;
+                                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                                               continue;
+                                       }
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#define DEPENDENCY_TIMEOUT 50
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       if (tmp.sec >= DEPENDENCY_TIMEOUT) {
+                                               printf("dep_tab[%d].flag %d disk_index %d line %s\n", dep_index,
+                                                       dep_tab[dep_index].flag, dep_tab[dep_index].disk_index,
+                                                       dep_tab[dep_index].line);
+                                       }
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_window_index.head;
+                                       for (j=CYCLIC_ADD(dep_index,1,dep_window_index.size); CYCLIC_LESS(dep_window_index,j,dep_window_index.head); j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else /*NO_DEPENDENCY_TABLE undefined */
+       /* this part of code will be invalid after CYCLIC buffer design */
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { 
+                                               /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+       struct ladtime current_time;
+
+       sfs_gettime (&current_time);    
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current_time.sec>timeout.sec) ||
+                               ((current_time.sec==timeout.sec) && (current_time.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_CANDIDATE);
+                               } else {
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_DONE);
+                               }
+                               timeout_num ++;
+                               num_out_reqs_statistics_at_timeout[num_out_reqs]++;
+
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               if (per_packet_debug)
+                                       printf ("timeout request: disk_index %d, dep_index %d biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", dep_tab[dep_index].disk_index, dep_index, biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+               num_out_reqs++;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if ((biod_reqp[biod_index].in_use == TRUE) &&( biod_reqp[biod_index].xid == xid)) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[TRACE_MSGID_POS], "%x %x", &msgid, &nfsproc);
+       //printf ("msgid %x nfsproc %x\n", msgid, nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+}
+
+void adjust_play_window (int flag, int * poll_timeout_arg)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int i;
+       char * line;
+       cyclic_index_t old_dep_window_index = dep_window_index;
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, begin\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("                adjust_play_window, begin\n");
+#endif
+
+       while ((!CYCLIC_EMPTY(dep_window_index)) && (dep_tab[dep_window_index.tail].flag == DEP_FLAG_DONE)) {
+#ifdef notdef
+               //CYCLIC_PRINT (memory_trace_index);
+               //printf("MOVE_TAIL_TO memory_index %d\n", dep_tab[dep_tab_index.tail].memory_index);
+               RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+               RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+               printf("%d is done\n", dep_window_index.tail);
+#endif
+               CYCLIC_MOVE_TAIL(dep_tab_index);
+               CYCLIC_MOVE_TAIL(dep_window_index);
+
+#ifdef notdef
+               CYCLIC_PRINT (dep_tab_index);
+               CYCLIC_PRINT (dep_window_index);
+
+               if (! (dep_tab_index.tail == dep_window_index.tail)) {
+                       CYCLIC_PRINT(dep_tab_index);
+                       CYCLIC_PRINT(dep_window_index);
+               };
+               RFS_ASSERT ( dep_tab_index.tail == dep_window_index.tail);
+#endif
+
+               if (!CYCLIC_EMPTY(dep_tab_index)) {
+#ifdef notdef
+                       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+                       if (!(CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head))) {
+                               CYCLIC_PRINT(memory_trace_index);
+                               CYCLIC_PRINT(dep_tab_index);
+                               printf("dep_tab[head-1].memory_index, %d [tail].memory_index %d\n", 
+                                       dep_tab[CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size)].memory_index,
+                                       dep_tab[dep_tab_index.tail].memory_index);
+                       }
+                       RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+#endif
+                       CYCLIC_SET_TAIL_TO(&memory_trace_index, dep_tab[dep_tab_index.tail].memory_index);
+                       //printf ("set memory_trace_index to %d=%d, dep_tab_index.tail %d\n", memory_trace_index.tail, dep_tab[dep_tab_index.tail].memory_index, dep_tab_index.tail);
+               } else {
+               //      CYCLIC_MOVE_TAIL (memory_trace_index);
+               }
+       }
+
+       while (CYCLIC_EMPTY(dep_tab_index)) {
+               
+               if (disk_io_status == TRACE_FILE_END) 
+                       return;
+               else {
+                       //printf ("************** ADJUST_PLAY_WINDOW sleep 1 s\n"); 
+                       //print_cyclic_buffers();
+                       //pthread_yield();
+                       //usleep (1000);
+               }
+       }
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (CYCLIC_NUM(dep_window_index) == MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, dep_tab_size %d dep_window_max %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", dep_tab_size, dep_window_max, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               struct ladtime t;
+               int dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+        t.sec = dep_tab[dep_index].timestamp.tv_sec;
+        t.usec = dep_tab[dep_index].timestamp.tv_usec;
+               if ((t.sec>max_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec))
+            break;
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout_arg = 0;
+       else if (CYCLIC_NUM(dep_window_index)==CYCLIC_NUM(dep_tab_index)) {
+               *poll_timeout_arg = 1000;       /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_index.head].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_index.head].timestamp.tv_usec;
+               if (adjust_play_window_debug>=2)
+                       printf ("dep_tab[dep_window_index.head %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_index.head, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+/*
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_max, dep_tab[dep_window_max].timestamp.tv_sec, dep_tab[dep_window_max].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+*/
+
+               //RFS_ASSERT ((tmp.sec < 1000));
+               if (tmp.sec > 1000)
+                       tmp.sec = 1000;
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout_arg = 0;
+               } else
+                       *poll_timeout_arg = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_max].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_max].timestamp.tv_usec;
+               tmp1.sec = dep_tab[dep_window_max-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[dep_window_max-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout_arg = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout_arg %d \n", 
+               flag, old_dep_window_index.tail, dep_window_index.tail, old_dep_window_index.head,
+               dep_window_index.head, *poll_timeout_arg);
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, end\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("        adjust_play_window, end\n\n");
+#endif
+       //CYCLIC_ASSERT(4);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+#ifdef RECV_THREAD
+       //printf("recv thread waitsem 1\n");
+       waitsem (async_rpc_sem);
+       //printf("recv thread got sem 1\n");
+#endif
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       //printf("recv thread waitsem 2\n");
+                       //waitsem (async_rpc_sem);
+                       //printf("recv thread got sem 2\n");
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       //postsem (async_rpc_sem);
+                       //printf("recv thread postsem 2\n");
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+#ifdef RECV_THREAD
+       postsem (async_rpc_sem);
+       //printf("recv thread postsem 1\n");
+#endif
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+#if    0       /* commented out by G. Jason Peng */
+       RFS_ASSERT (read_data_owe_GB==0);
+       printf("read_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",read_data_total_GB, read_data_total, read_data_owe_GB, read_data_owe, (read_data_owe)/(read_data_total/100), read_data_adjust_times);
+       printf("write_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",write_data_total_GB, write_data_total, write_data_owe_GB, write_data_owe, (write_data_owe)/(write_data_total/100), write_data_adjust_times);
+       printf("poll_timeout_0_num %d poll_timeout_pos_num %d\n", poll_timeout_0_num, poll_timeout_pos_num);
+       printf("failed_create_command_num_in_original_trace %d\nfailed_other_command_num_in_original_trace %d\nskipped_readlink_command_num %d\nskipped_custom_command_num %d\nfh_path_map_err_num %d\nskipped_fsstat_command_num %d\nmissing_reply_num %d\nrename_rmdir_noent_reply_num %d\nrmdir_not_empty_reply_num %d\nloose_access_control_reply_num %d\nlookup_err_due_to_rename %d\nlookup_err_due_to_parallel_remove %d\nlookup_eaccess_enoent_mismatch %d\nread_io_err_num %d\nstale_fhandle_err_num %d abnormal_EEXIST_num %d abnormal_ENOENT_num %d proper_reply_num %d run_stage_proper_reply_num %d\n", 
+                       failed_create_command_num,
+                       failed_other_command_num,
+                       skipped_readlink_command_num, 
+                       skipped_custom_command_num,
+                       fh_path_map_err_num, 
+                       skipped_fsstat_command_num, 
+                       missing_reply_num, 
+                       rename_rmdir_noent_reply_num, 
+                       rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, 
+                       lookup_err_due_to_rename_num, 
+                       lookup_err_due_to_parallel_remove_num,
+                       lookup_eaccess_enoent_mismatch_num, 
+                       read_io_err_num, 
+                       stale_fhandle_err_num,
+                       abnormal_EEXIST_num,
+                       abnormal_ENOENT_num,
+                       proper_reply_num, run_stage_proper_reply_num);
+#endif
+
+//  print_dump(Client_num, Child_num);
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               //RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               if (memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE)) {
+                       int i;
+                       printf ("fh_map[%d].trace_fh %s trace_fh %s", p->key3, fh_map[p->key3].trace_fh, trace_fh);
+                       for (i=0; i<fh_i; i++) {
+                               int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                               int * p = (int *)fh_map[i].trace_fh;
+                               printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                               printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, fh_map[i].trace_fh, fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+                       }
+#endif
+                       RFS_ASSERT (0);
+               }
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               /* It's possible that in fh-path-map, many trace_fh are corresponding to one path
+                * some of it may be the result of lookup after symlink, which is not handled
+                * properly as new created objects 
+                */
+#ifdef TAKE_CARE_SYMBOLIC_LINK
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+#endif
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       strncpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       //show_fhandle(play_fh);
+               } else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+inline fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i[%d] trace_fh %s path %s play_fh:\n", p->key3, fh_map[p->key3].trace_fh, fh_map[p->key3].path);
+                       //show_fhandle(&fh_map[p->key3].play_fh);
+               }
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+int lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+       return (reply.status);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[MAX_TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+       int lineno = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       if (strstr(fh_map_file, "fmt1")) {
+               TRACE_FH_SIZE = 48;
+       }
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               lineno ++;
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7) ||
+                       !strncmp (trace_path, "LN", 2)                  ) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       int ret = lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);               
+                       if (ret!=NFS3_OK) {
+                               printf ("lineno %d %s\n", lineno, buf);
+                       }
+                       RFS_ASSERT (ret == NFS3_OK);
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline free_biod_req (int biod_index)
+{
+       RFS_ASSERT (biod_reqp[biod_index].in_use == TRUE);
+       biod_reqp[biod_index].in_use = FALSE;
+       num_out_reqs --;
+}
+
+void finish_request (int biod_index, int dep_index, int status, int dep_flag)
+{
+       static int i = 0;
+       /* the ending operation, same as when a request time out */
+
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       free_biod_req (biod_index);
+
+       dep_tab[dep_index].status = status;
+
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = -dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].flag = dep_flag;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+       static int last_print_time = -1;
+
+       if (num_out_reqs == max_biod_reqs) {
+               return -1;
+       }
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+
+       if (per_packet_debug)
+               fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+
+       end_profile(&total_profile);
+       if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+               last_print_time = total_profile.in.tv_sec;
+               //fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+/*
+               CYCLIC_PRINT (dep_tab_index);
+               {
+                       int tmp = CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size);
+                       printf("dep_tab_index.head-1 %d disk_index %d tail %d disk_index %d\n", tmp, dep_tab[tmp].disk_index,
+                       dep_tab_index.tail, dep_tab[dep_tab_index.tail].disk_index);
+               }
+*/
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+/*
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+*/
+#endif
+               if ((total_profile.in.tv_sec > 100)) {
+                       can_not_catch_speed_num_total += can_not_catch_speed_num;
+               }
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+#ifdef notdef  /* place to set request timeout. G. Jason Peng */
+       call_timeout.sec = 2; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+#else
+       call_timeout.sec = 0;
+       call_timeout.usec = 300000;
+       //call_timeout.usec = 14000;
+       //call_timeout.usec = 13000;
+       //call_timeout.usec = 6000;
+       //call_timeout.usec = 8000;
+       //call_timeout.usec = 10000;
+#endif
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+
+#ifdef RECV_THREAD
+       //printf ("send thread waitsem\n");
+       waitsem(async_rpc_sem);
+       //printf ("send thread got sem\n");
+#endif
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#ifdef RECV_THREAD
+       postsem(async_rpc_sem);
+       //printf ("send thread postsem\n");
+#endif
+
+#else  // REAL_PLAY
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    RFS_ASSERT (reqp->xid != 0);
+    reqp->timeout = reqp->start;
+    ADDTIME (reqp->timeout, call_timeout);
+    dep_tab[dep_index].flag = DEP_FLAG_SENT;
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+
+       send_num ++;
+}
+
+void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_status)
+{
+       if (((status!=trace_status)) && (status!=NFS3_OK) && (trace_status!=NFS3ERR_RFS_MISS)) {
+               if (!profile_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else // if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_status == 0)) {
+                               /* trace_status could be EAGAIN */
+                       if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) ) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+               } else if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status == NFS3ERR_NOENT)) {
+                       /* if there is a remove in front of the lookup, but it is
+                        * actually executed later than the lookup
+                        */
+                       lookup_err_due_to_parallel_remove_num ++;
+#endif
+#ifndef TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+               /* if the looked return EACCESS in the trace, means the object still exists
+                * should have initialized, right not don't initialize it, hence play status 
+                * could be ENOENT
+                */
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3ERR_ACCES)) {
+                       lookup_eaccess_enoent_mismatch_num ++;
+#endif
+#ifdef TOLERANT_READ_IO_ERR
+               } else if ((proc==READ) && (status==NFS3ERR_IO) && (trace_status==NFS3_OK)) {
+                       read_io_err_num ++;
+#endif
+#ifdef TOLERANT_STALE_FHANDLE_ERR
+               } else if ((status==NFS3ERR_STALE) && (trace_status==NFS3_OK)) {
+                       printf ("!!!!!!! STALE FILE HANDLE \n");
+                       //sleep(1);
+                       stale_fhandle_err_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=dep_window_index.tail; CYCLIC_LESS(dep_window_index,i,dep_window_index.head); i++) {
+                               if (dep_tab[i].flag!=1)
+                                       printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       }
+
+                       if (status==EEXIST) {
+                               abnormal_EEXIST_num ++;
+                       } else if (status == ENOENT) {
+                               abnormal_ENOENT_num ++;
+                       } else {
+                               printf ("!!!!!!!!!!!!!1 should fail\n");
+                               //RFS_ASSERT (0);
+                       }
+               }
+       } else {
+               proper_reply_num ++;
+               if (total_profile.in.tv_sec >= WARMUP_TIME) 
+                       run_stage_proper_reply_num ++;
+       }
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_status;
+       char * errmsg;
+       int poll_timeout = 0;           /* timeout in usecs */
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+
+       if (busy_flag == BUSY) {
+               poll_timeout = 0;
+               poll_timeout_0_num ++;
+       } else {
+               poll_timeout = 2000;    /* 10000 or 2000 is a better number in non-debugging state */
+               //poll_timeout = 0;     /* 10000 or 2000 is a better number in non-debugging state */
+               poll_timeout_pos_num ++;
+       }
+
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       if (biod_reqp[biod_index].in_use==1) {
+               RFS_ASSERT (dep_tab[dep_index].biod_req_index == biod_index);
+       } else {
+               printf ("biod_index %d reply received but the request has been time out\n", biod_index);
+               return -1;
+       }
+
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = dep_tab[dep_index].reply_line;
+       trace_status = dep_tab[dep_index].trace_status;
+
+       if (per_packet_debug || rfs_debug )
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status, DEP_FLAG_DONE);
+       recv_num ++;
+       
+       /* we set 100 seconds warm up time */
+       if ((total_profile.in.tv_sec >= WARMUP_TIME)) {
+       /* get statistics */
+       if (status == trace_status || (status==NFS3_OK && trace_status==NFS3ERR_RFS_MISS) ) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       }
+       
+       //start_profile (&add_create_object_profile);
+
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+               RFS_ASSERT (reply_line);
+#endif
+               if (status!=NFS3_OK) {
+                       /* commented out for 1022 */
+                       printf ("!!!!!! Should have been an ASSERTION FAILURE \n");
+                       RFS_ASSERT (proc==SYMLINK);
+                       RFS_ASSERT (0);
+               } else {
+                       if (proc!=SYMLINK || line[TRACE_VERSION_POS]!='2')
+                               add_new_file_system_object(proc, dep_index, line, reply_line);
+               }
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+       reply_trace_fh = dep_tab[dep_index].reply_trace_fh;
+#else
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+#endif
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+#endif
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       /* just to preserve the original reply line not changed */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+#endif
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, dep_window_max> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+       static int last_print_time = -1;
+       int poll_timeout = 0;
+
+#ifndef IO_THREAD
+       disk_io_status = read_trace();
+#endif
+
+       RFS_ASSERT (!CYCLIC_EMPTY(dep_tab_index));
+       CYCLIC_MOVE_HEAD(dep_window_index);
+
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while (!CYCLIC_EMPTY(dep_tab_index)) {
+               end_profile(&total_profile);
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       int i;
+
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, ">>>> sendng thread: time %d send_num %d recv_num %d timeout_num %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, send_num, recv_num, timeout_num, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics[i]!=0) {
+                                       printf("num_out_req[%d]=%d,", i, num_out_reqs_statistics[i]);
+                                       num_out_reqs_statistics[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics_at_timeout[i]!=0) {
+                                       printf("num_out_req_at_timeout[%d]=%d,", i, num_out_reqs_statistics_at_timeout[i]);
+                                       num_out_reqs_statistics_at_timeout[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       //      CYCLIC_PRINT(dep_tab_index);
+               }
+
+               if ((total_profile.in.tv_sec > 6000)) {
+                       printf ("the process has run for more than 600 seconds, exit\n");
+                       goto END;
+               }
+
+               if (busy_flag == IDLE) {
+#ifndef RECV_THREAD
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+#endif
+#ifndef IO_THREAD
+                       if (disk_io_status!=TRACE_FILE_END) {
+                               disk_io_status = read_trace();
+                       };
+#endif
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               num_out_reqs_statistics[num_out_reqs]++;
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1) {
+                       busy_flag = BUSY;
+               }
+               end_profile (&execute_next_request_profile);
+
+#ifndef RECV_THREAD
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+#endif
+               end_profile (&receive_next_reply_profile);
+#endif
+               CYCLIC_ASSERT (0);
+       }
+       end_profile (&total_profile);
+
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       if (num_out_reqs !=0 ) {
+               printf ("num_out_reqs %d\n", num_out_reqs);
+               CYCLIC_PRINT(dep_tab_index);
+       }
+       RFS_ASSERT(num_out_reqs==0);
+
+END:
+       printf ("trace starttime %d, trace_end_time %d trace_duration %d\n", trace_timestamp1, trace_timestamp2,
+               trace_timestamp2 - trace_timestamp1);
+       printf ("can_not_catch_speed_num_total %d can_not_catch_speed_num_last_10_seconds %d", 
+               can_not_catch_speed_num_total, can_not_catch_speed_num);
+       printf ("total_profile.about: %s\n", total_profile.about);
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       //print_profile ("check_timeout", &check_timeout_profile);
+       //printf("\n");
+       //print_profile ("adjust_play_window", &adjust_play_window_profile);
+       //printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument_profile", &prepare_argument_profile);
+       print_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply_profile", &decode_reply_profile);
+       print_profile ("check_reply_profile", &check_reply_profile);
+       print_profile ("fgets_profile", &fgets_profile);
+       print_profile ("read_line_profile", &read_line_profile);
+       print_profile ("read_trace_profile", &read_trace_profile);
+       //print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("dep_tab_index.tail %d dep_tab_index.head %d num_out_reqs %d\n", dep_tab_index.tail, dep_tab_index.head, num_out_reqs);
+}
+
+
+int CYCLIC_SET_TAIL_TO(cyclic_index_t * index, int dest) 
+{ 
+       cyclic_index_t indextmp, indextmp2;
+       int oldnum, num;
+       indextmp = *index;
+       indextmp2 = indextmp;
+       oldnum = CYCLIC_NUM(indextmp); 
+
+       if (! ((dest>=0) && (dest<indextmp.size))) {
+               CYCLIC_PRINT(indextmp);
+               printf("dest %d\n", dest);
+       }
+       RFS_ASSERT ((dest>=0) && (dest<indextmp.size));
+       index->tail = dest; 
+       indextmp2.tail = dest;
+       num = CYCLIC_NUM(indextmp2); 
+
+       if (num > oldnum) { 
+               CYCLIC_PRINT(indextmp);
+               CYCLIC_PRINT(indextmp2);
+               printf("dest %d old_num %d num %d\n", dest, oldnum, num);
+       }
+       RFS_ASSERT (num <= oldnum);
+}
+
+int flush_junk()
+{
+       int i;
+       for (i=0; i<500; i++) {
+               printf ("*************************************************************\n");
+       }
+       fflush(stdout);
+}
+
+int CYCLIC_ASSERT (int i)
+{
+       int j;
+       if (!(dep_tab_index.tail == dep_window_index.tail)) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       if (!((dep_window_index.head == dep_tab_index.head) || 
+                  CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ) )) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       for (i=0, j=0; i<max_biod_reqs; i++) {
+               if (biod_reqp[i].in_use == 1)
+                       j++;
+       }
+#ifndef RECV_THREAD
+       RFS_ASSERT (num_out_reqs==j);
+#endif
+/*
+               RFS_ASSERT ((dep_window_index.head == dep_tab_index.head) || 
+                          CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ));
+*/
+}
+
+/* sfs_c_chd.c */
diff --git a/TBBT/trace_play/sfs_c_clk.c b/TBBT/trace_play/sfs_c_clk.c
new file mode 100644 (file)
index 0000000..afe9a44
--- /dev/null
@@ -0,0 +1,309 @@
+#ifndef lint
+static char sfs_c_clkSid[] = "@(#)sfs_c_clk.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_clk.c ---------------------
+ *
+ *      Clock handling.  Routines to read the clock, measure elapsed
+ *     time and sleep for a timed interval.
+ *
+ *.Exported_Routines
+ *     void sfs_gettime(struct ladtime *)
+ *     void sfs_elapsedtime(sfs_op_type *, struct ladtime *,
+ *                             struct ladtime *)
+ *     int msec_sleep(int)
+ *
+ *.Local_Routines
+ *     None.
+ *
+ *.Revision_History
+ *     05-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/signal.h>
+
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+#if !(defined(USE_GETTIMEOFDAY) || defined(USE_TIMES))
+#define USE_GETTIMEOFDAY
+#endif
+
+#define CLK_RESOLUTION         10      /* clock resolution in msec */
+
+/*
+ * -------------------------  Clock Handling  -------------------------
+ */
+
+#if defined(USE_GETTIMEOFDAY)
+/*
+ * The time that the test first starts, all times are relative to this
+ * value to prevent integer overflows.
+ */
+extern struct ladtime  test_start = {0, 0, 0};
+
+/*
+ * Get the time of day, offset by 'tz_ptr', and return it in 'time_ptr'.
+ * This is a local time of day interface to allow support for system
+ * dependent clock resolution.
+ */
+void
+sfs_gettime(
+    struct ladtime     *time_ptr)
+{
+       time_t          t;
+       struct timeval  tv;
+
+       (void) gettimeofday(&tv, NULL);
+       /*
+        * Use standard time function to get epoch time since 1970 for
+        * setattr/create.
+        */
+       t = time((time_t *)NULL);
+
+       if (test_start.sec == 0 && test_start.usec == 0) {
+               test_start.sec = tv.tv_sec;
+               test_start.usec = 0;
+       }
+       time_ptr->sec = tv.tv_sec - test_start.sec;
+       time_ptr->usec = tv.tv_usec;
+
+       time_ptr->esec = (int32_t)t;
+} /* sfs_gettime */
+#endif /* USE_GETTIMEOFDAY */
+
+#if defined(USE_TIMES)
+static uint32_t        test_start = 0;
+
+void
+sfs_gettime(
+       struct ladtime  *time_ptr)
+{
+       time_t          t;
+       uint32_t        clock_ticks;
+       struct tms      tms;
+       int32_t         ticks_per_sec = 100;
+
+       /*
+        * Try use possible conversions from least accurate to most accurate
+        */
+#if defined(HZ)
+       ticks_per_sec = HZ;
+#endif /* HZ */
+#if defined(CLK_TCK)
+       ticks_per_sec = CLK_TCK;
+#endif /* CLK_TCK */
+#if defined(_SC_CLK_TCK)
+       ticks_per_sec = sysconf(_SC_CLK_TCK);
+#endif /* _SC_CLK_TCK */
+
+       if ((clock_ticks = (uint32_t)times(&tms)) == -1) {
+               (void) fprintf(stderr, "%s: can't get time of day from system: %s\n",
+                       sfs_Myname, strerror(errno));
+               (void) generic_kill(0, SIGINT);
+               exit(175);
+       }
+
+       /*
+        * Use standard time function to get epoch time since 1970 for
+        * setattr/create.
+        */
+       t = time((time_t *)NULL);
+
+       if (test_start == 0) {
+               test_start = clock_ticks;
+       }
+
+       time_ptr->sec = (clock_ticks - test_start) / ticks_per_sec;
+       time_ptr->usec = ((clock_ticks - test_start) -
+                                       (time_ptr->sec * ticks_per_sec)) *
+                                       (1000000/ticks_per_sec);
+       time_ptr->esec = (int32_t)t;
+}
+#endif /* USE_TIMES */
+
+/*
+ * Compute the elapsed time between 'stop_ptr' and 'start_ptr', and
+ * add the result to the time acculated for operation 'op_ptr'.
+ */
+void
+sfs_elapsedtime(
+       sfs_op_type *   op_ptr,
+       struct ladtime *        start_ptr,
+       struct ladtime *        stop_ptr)
+{
+       double  msec2;
+       struct ladtime time_ptr1, time_ptr2;
+
+       /* get the elapsed time */
+       if (stop_ptr->usec >= 1000000) {
+               stop_ptr->sec += (stop_ptr->usec / 1000000);
+               stop_ptr->usec %= 1000000;
+       }
+
+       if (stop_ptr->usec < start_ptr->usec) {
+               stop_ptr->usec += 1000000;
+               stop_ptr->sec--;
+       }
+
+       if (stop_ptr->sec < start_ptr->sec) {
+               stop_ptr->sec = 0;
+               stop_ptr->usec = 0;;
+       } else {
+               stop_ptr->usec -= start_ptr->usec;
+               stop_ptr->sec -= start_ptr->sec;
+       }
+
+       /* count ops that take zero time */
+       if ((stop_ptr->sec == 0) && (stop_ptr->usec == 0))
+               op_ptr->results.fast_calls++;
+
+       /* add the elapsed time to the total time for this operation */
+
+       time_ptr1 = op_ptr->results.time;
+       time_ptr2 = *stop_ptr;
+
+       ADDTIME(time_ptr1, time_ptr2);
+
+       op_ptr->results.time = time_ptr1;
+       stop_ptr = &time_ptr2;
+
+       /* square the elapsed time */
+       msec2 = (stop_ptr->sec * 1000.0) + (stop_ptr->usec / 1000.0);
+       msec2 *= msec2;
+
+       /* add the squared elapsed time to the total of squared elapsed time */
+       op_ptr->results.msec2 += msec2;
+
+       /*
+        * Log this point if logging is on. The (op_ptr - Ops)
+        * calculation is a baroque way of deriving the "NFS Operation
+        * code" we just executed--given available information.
+        *
+        * stop_ptr at this time contains the *elapsed* time, or
+        * response time of the operation.
+        */
+        log_dump(start_ptr, stop_ptr, op_ptr - Ops);
+
+} /* sfs_elapsedtime */
+
+long cumulative_resets;
+long cumulative_adjusts;
+long msec_calls;
+/*
+ * Use select to sleep for 'msec' milliseconds.
+ * Granularity is CLK_RESOLUTION msec.
+ * Return the amount we actually slept.
+ */
+int
+msec_sleep(
+       int             msecs)
+{
+       int             actual_msecs;
+       static long     cumulative_error_msecs = 0;
+       int             select_msecs;
+       struct timeval  sleeptime;
+       int             Saveerrno;
+       struct ladtime  start;
+       struct ladtime  end;
+
+       sfs_gettime(&start);
+
+       select_msecs = msecs + cumulative_error_msecs;
+        if (select_msecs < 0) {
+               sleeptime.tv_sec = 0;
+               sleeptime.tv_usec = 0;
+        } else {
+               sleeptime.tv_sec = select_msecs / 1000;
+               sleeptime.tv_usec = (select_msecs % 1000) * 1000;
+        }
+
+       /* sleep */
+       if (select(0, NULL, NULL, NULL, &sleeptime) == -1) {
+               if (errno != EINTR) {
+                       Saveerrno = errno;
+                       (void) fprintf(stderr, "%s: select failed ",
+                                                               sfs_Myname);
+                       errno = Saveerrno;
+                       perror("select");
+                       (void) generic_kill(0, SIGINT);
+                       exit(176);
+               }
+       }
+       sfs_gettime(&end);
+
+       SUBTIME(end, start);
+       actual_msecs = ((end.sec * 1000) + (end.usec / 1000));
+
+       cumulative_error_msecs += (msecs - actual_msecs);
+       if(cumulative_error_msecs > 100 ||
+               cumulative_error_msecs < -100) /* Clip tops */
+       {
+                       cumulative_error_msecs = 0;
+                       cumulative_resets++;
+       }
+       else
+       {
+               if(cumulative_error_msecs != 0) 
+                       cumulative_adjusts++;
+       }
+       msec_calls++;
+       return actual_msecs;
+} /* msec_sleep */
+
+
+/* sfs_c_clk.c */
diff --git a/TBBT/trace_play/sfs_c_clnt.c b/TBBT/trace_play/sfs_c_clnt.c
new file mode 100644 (file)
index 0000000..6c18e0d
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef lint
+static char sfs_c_clntSid[] = "@(#)sfs_c_clnt.c        2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+#if !defined(_XOPEN_SOURCE)
+#include <sys/socket.h>
+#else
+#define        AF_INET         2
+#endif
+
+CLIENT *
+lad_clnt_create(int prot, struct hostent *hostent, uint32_t program,
+               uint32_t version, int sock, struct timeval *wait)
+{
+       struct sockaddr_in      sin;
+       CLIENT                  *client_ptr;
+       uint_t                  sendsz = 0;
+       uint_t                  recvsz = 0;
+
+       /* set up the socket address for the remote call */
+       (void) memset((char *) &sin, '\0',  sizeof(sin));
+       (void) memmove((char *) &sin.sin_addr,
+                       hostent->h_addr,
+                       hostent->h_length);
+        sin.sin_family = AF_INET;
+
+       switch (prot) {
+       case 0:                 /* UDP */
+               if (sendsz == 0)
+                       client_ptr = sfs_cudp_create(&sin, program, version,
+                                               *wait, &sock);
+               else
+                       client_ptr = sfs_cudp_bufcreate(&sin, program, version,
+                                               *wait, &sock,
+                                               sendsz, recvsz);
+               break;
+       case 1:                 /* TCP */
+               sendsz = NFS_MAXDATA + 1024;
+               recvsz = NFS_MAXDATA + 1024;
+
+               client_ptr = sfs_ctcp_create(&sin, program, version, &sock,
+                                               sendsz, recvsz);
+               break;
+       }
+
+       if (client_ptr == ((CLIENT *) NULL)) {
+               char    buf[128];
+
+               (void) sprintf(buf, "%s: server not responding",
+                            sfs_Myname);
+               clnt_pcreateerror(buf);
+               return((CLIENT *) NULL);
+       }
+
+       return (client_ptr);
+}
diff --git a/TBBT/trace_play/sfs_c_dat.c b/TBBT/trace_play/sfs_c_dat.c
new file mode 100644 (file)
index 0000000..a5fc22e
--- /dev/null
@@ -0,0 +1,339 @@
+#ifndef lint
+static char sfs_c_datSid[] = "@(#)sfs_c_dat.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *
+ * ------------------------- sfs_c_dat.c --------------------------
+ *
+ *      Space declarations for sfs.
+ *
+ *.Revision_History
+ *      11-Jul-94      ChakChung Ng    Add codes for NFS/v3
+ *      24-Aug-92      Wittle          New file set access.
+ *      05-Jan-92      Pawlowski       Added hooks for raw data dump.
+ *      04-Dec-91      Bruce Keith     Include string.h for SYSV/SVR4.
+ *     17-May-90       Richard Bean    Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+
+/*
+ * -------------------------  NFS Operations  -------------------------
+ */
+
+/*
+ * RPC timeout values by call type.
+ * Index'ed by #defines in sfs_def.h.
+ */
+struct timeval *Nfs_timers;
+
+struct timeval Nfs_udp_timers[] = {
+
+       /* secs  usecs */
+       {  10,    0 },          /* All commands during initialization phase */
+       {   1,    0 },          /* Lookup during warmup and test run phases */
+       {   2,    0 },          /* Read during warmup and test run phases */
+       {   3,    0 },          /* Write during warmup and test run phases */
+};
+
+/*
+ * TCP is a "reliable" protocol so timeouts should never occur.  Set
+ * the values to be large enough to ensure all servers will respond
+ * but not too large so a broken implementation will still complete.
+ */
+struct timeval Nfs_tcp_timers[] = {
+
+       /* secs  usecs */
+       {  60,    0 },          /* All commands during initialization phase */
+       {  60,    0 },          /* Lookup during warmup and test run phases */
+       {  60,    0 },          /* Read during warmup and test run phases */
+       {  60,    0 },          /* Write during warmup and test run phases */
+};
+
+/*
+ * -----------------------  Transfer Size Distribution  -----------------------
+ *
+ * Over-the-wire transfer sizes are divided into 2 cases: read and write.
+ * For each case, a percentile rank determines the basic size unit of the
+ * transfer which is multiplied by a count to give the total size for the
+ * percentile.
+ *
+ * The block transfer size distribution is specified by a table of values.
+ * The first column gives the percent of operations that will be a
+ * specific block transfer size.  The second column gives the number of
+ * blocks units that will be transferred.  Normally the block unit size
+ * is 8KB.  The third column is a boolean specifying whether a trailing
+ * fragment block should be transferred.  The fragment size for each transfer
+ * is a random multiple of 1 KB, up to the block size - 1 KB.  Two tables
+ * are needed, one for read operation and one for write operations.  The
+ * following table gives the default distributions.
+ *
+ *     Read  - Default Block Transfer Size Distribution Table
+ * percent   block count   fragment    resulting transfer (8KB block size)
+ * -------   -----------   --------    -----------------------------------
+ *    0        0             0                  0%    1 -   7 KB
+ *   85        1             0                 85%    9 -  15 KB
+ *    8        2             1                  8%   17 -  23 KB
+ *    4        4             1                  4%   33 -  39 KB
+ *    2        8             1                  2%   65 -  71 KB
+ *    1       16             1                  1%  129 - 135 KB
+ *
+ *     Write  - Default Block Transfer Size Distribution Table
+ * percent   block count   fragment    resulting transfer (8KB block size)
+ * -------   -----------   --------    -----------------------------------
+ *   49        0             1         49%    1 -   7 KB
+ *   36        1             1         36%    9 -  15 KB
+ *    8        2             1           8%   17 -  23 KB
+ *    4        4             1          4%   33 -  39 KB
+ *    2        8             1          2%   65 -  71 KB
+ *    1       16             1          1%  129 - 135 KB
+ *
+ * The user may specify a a different distribution by using the '-b' option.
+ * The format for the block size distribution file consists of the first
+ * three columns given above: percent, block count, and fragment.  Read
+ * and write distribution tables are identified by the keywords "Read" and
+ * "Write".  An example input file, using the default values, is given below:
+ *
+ *             Read
+ *              0  0  0
+ *             85  1  0
+ *              8  2  1
+ *              4  4  1
+ *              2  8  1
+ *              1 16  1
+ *             Write
+ *             49  0  1
+ *             36  1  1
+ *              8  2  1
+ *              4  4  1
+ *               2  8  1
+ *               1 16  1
+ *
+ * A second parameter controlled by the block transfer size distribution table
+ * is the network transport packet size.  The distribution tables define the
+ * relative proportion of full blocks packets to fragment packets.  For
+ * instance, the default tables have been constructed to produce a specific
+ * distribution of ethernet packet sizes for i/o operations by controlling
+ * the amount of data in each packet.  The write packets produced consist
+ * of 50% 8-KB packets, and 50% 1-7 KB packets.  The read packets consist
+ * of 85% 8-KB packets, and 15% 1-7 KB packets.  These figures are
+ * determined by multiplying the percentage for the type of transfer by
+ * the number of blocks and fragments generated, and adding the totals.
+ * These conmputations are performed below for the default block size
+ * distribution tables:
+ *
+ *             Read            blocks          fragments
+ *              0  0  0          0               0
+ *             85  1  0         85               0
+ *              8  2  1         16               8
+ *              4  4  1         16               4
+ *              2  8  1         16               2
+ *              1 16  1         16               1
+ *                             ---             ---
+ *                             149 (90%)        15 (10%)
+ *
+ *             Write
+ *             49  0  1          0              49
+ *             36  1  1         36              36
+ *              8  2  1         16               8
+ *              4  4  1         16               4
+ *               2  8  1        16               2
+ *               1 16  1        16               1
+ *                             ---             ---
+ *                             100 (50%)       100 (50%)
+ *
+ *
+ */
+static sfs_io_op_dist_type Default_read_size_dist[] = {
+       /* percentile   8KB xfers       fragments                       */
+       {        0,      0,             0 },    /*   0%    1 -   7 KB   */
+       {       85,      1,             0 },    /*  85%    8       KB   */
+       {       93,      2,             1 },    /*   8%   17 -  23 KB   */
+       {       97,      4,             1 },    /*   4%   33 -  39 KB   */
+       {       99,      8,             1 },    /*   2%   65 -  71 KB   */
+       {      100,     16,             1 },    /*   1%  129 - 135 KB   */
+};
+
+static sfs_io_op_dist_type Default_write_size_dist[] = {
+       /* percentile   8KB xfers       fragments                       */
+       {       49,      0,             1 },    /*  49%    1 -   7 KB   */
+       {       85,      1,             1 },    /*  36%    9 -  15 KB   */
+       {       93,      2,             1 },    /*   8%   17 -  23 KB   */
+       {       97,      4,             1 },    /*   4%   33 -  39 KB   */
+       {       99,      8,             1 },    /*   2%   65 -  71 KB   */
+       {      100,     16,             1 },    /*   1%  129 - 135 KB   */
+};
+
+static sfs_io_dist_type Default_io_dist = {
+       Default_read_size_dist,         /* read size distribution */
+       Default_write_size_dist,        /* write size distribution */
+       17,                             /* max file size in Block_size units */
+       1.64,                           /* average read ops / request */
+       2                               /* average write ops / request */
+};
+
+sfs_io_file_size_dist Default_file_size_dist[] = {
+       /* percentage   KB size */
+       {        33,      1},                   /* 33% */
+       {        54,      2},                   /* 21% */
+       {        67,      4},                   /* 13% */
+       {        77,      8},                   /* 10% */
+       {        85,     16},                   /*  8% */
+       {        90,     32},                   /*  5% */
+       {        94,     64},                   /*  4% */
+       {        97,    128},                   /*  3% */
+       {        99,    256},                   /*  2% */
+       {       100,   1024},                   /*  1% */
+       {         0,      0}
+};
+
+/*
+ * -------------------------  Remote File Information  -------------------------
+ */
+int  Num_io_file_sizes;                        /* # of different size of files */
+int  Num_io_files;                     /* # of files used for i/o */
+int  Num_non_io_files;                 /* # of non-i/o regular files */
+int  Num_dirs;                         /* # of pre-created directories */
+int  Num_dir_files;                    /* # of directories */
+int  Num_symlinks;                     /* # of pre-created symlinks */
+int  Num_symlink_files;                        /* # of symlinks  */
+
+int  Num_working_io_files;             /* # of i/o files in working set */
+int  Num_working_non_io_files;         /* # of non i/o files in working set */
+int  Num_working_dirs;                 /* # of dirs in working set */
+int  Num_working_symlinks;             /* # of symlinks in working set */
+int  files_per_megabyte;               /* # of files created of each MB */
+
+
+sfs_io_dist_type *Io_dist_ptr=  /* block transfer distribution info */
+                       &Default_io_dist;
+
+sfs_fh_type            *Io_files;      /* list of i/o files  */
+sfs_fh_type            *Non_io_files;  /* list of non-i/o files */
+sfs_fh_type            *Dirs;          /* list of directories */
+sfs_fh_type            *Symlinks;      /* list of symlinks */
+
+sfs_fh_type    *Cur_file_ptr;          /* current file */
+char   Cur_filename[SFS_MAXNAMLEN];    /* current dir entry name */
+char   Filespec[SFS_MAXNAMLEN] /* sprintf spec for file names */
+                    = "file_en.%05d";
+char   Dirspec[SFS_MAXNAMLEN]  /* sprintf spec for directory names */
+                    = "dir_ent.%05d";
+char   Symspec[SFS_MAXNAMLEN]  /* sprintf spec for symlink names */
+                    = "symlink.%05d";
+
+/*
+ * -------------------------  Run Parameters -------------------------
+ */
+
+int    nfs_version;
+sfs_phase_type Current_test_phase;     /* current phase of the test */
+
+sfs_fh_type    Export_dir;                     /* filehandle for exported fs */
+CLIENT *       NFS_client;                     /* RPC client handle */
+CLIENT *       NFS_client_recv;        /* RPC client handle used for recv_thread */
+
+bool_t Timed_run = TRUE;                       /* Timed run or call target ? */
+int    Runtime = DEFAULT_RUNTIME;              /* seconds in benchmark run */
+int    Warmuptime = DEFAULT_WARMUP;            /* seconds to warmup */
+int    Access_percent = DEFAULT_ACCESS;        /* % of file set to access */
+int    Append_percent = DEFAULT_APPEND;        /* % of writes that append */
+int    Fss_delta_percent = DEFAULT_DELTA_FSS;  /* allowed change to file set */
+int    Kb_per_block = DEFAULT_KB_PER_BLOCK;    /* i/o pkt block sz in KB */
+int    Bytes_per_block = DEFAULT_KB_PER_BLOCK * 1024;/* i/o pkt sz in bytes */
+int    Num_failed_lookup = DEFAULT_FAILED_LOOKUP; /* percent failed lookups */
+int    Testop = -1;                            /* test mode operation number */
+int    Interactive = 0;                        /* test synchronized by user*/
+int    Populate_only = 0;                      /* populate test dirs & quit */
+int    Debug_level = 0xFFFF;                   /* debugging switch */
+
+
+/*
+ * ---------------------  Biod Simulation Variables ---------------------
+ */
+
+int    Biod_max_outstanding_writes = DEFAULT_BIOD_MAX_WRITE;
+int    Biod_max_outstanding_reads = DEFAULT_BIOD_MAX_READ;
+
+
+/*
+ * -------------------  File Set Size Control -------------------------
+ */
+
+int    avg_bytes_per_file = 136*1024;  /* calculated average file size */
+int    Base_fss_bytes = 0;             /* base file set size in bytes */
+int    Most_fss_bytes = 0;             /* most bytes ever in file set */
+int    Least_fss_bytes = 0;            /* least bytes ever in file set */
+int    Limit_fss_bytes = 0;            /* target upper limit on fileset size */
+int    Cur_fss_bytes = 0;              /* bytes currently in file set */
+int    Total_fss_bytes = 0;            /* Total bytes created */
+
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+
+int    Msec_per_period;        /* total msec during the current run period */
+
+
+/*
+ * -------------------------  Miscellaneous  -------------------------
+ */
+
+struct ladtime Cur_time;               /* current time of day */
+struct ladtime Starttime;              /* start of test */
+int            start_run_phase = 0; 
+
+char   lad_hostname[HOSTNAME_LEN];
+/* sfs_c_dat.c */
diff --git a/TBBT/trace_play/sfs_c_def.h b/TBBT/trace_play/sfs_c_def.h
new file mode 100644 (file)
index 0000000..e35e73d
--- /dev/null
@@ -0,0 +1,634 @@
+#ifndef _sfs_c_def_h
+#define _sfs_c_def_h
+
+#define RFS
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * @(#)sfs_c_def.h     2.1     97/10/23
+ *
+ * -------------------------- sfs_c_def.h -----------------------
+ *
+ *      Literals and types for the sfs program.
+ *
+ *.Revision_History
+ *      Wittle          24-Aug-92     - New file set access code.
+ *      Bruce Keith     04-Dec-91     - Fix SVR4 definitions for NGROUPS.
+ *                                    - Include param.h/limits.h as
+ *                                      appropriate (BSD/SVR4).
+ *                                    - Use bcopy, bzero, bcmp for BSD;
+ *                                      memcpy, memset, memcmp for SYSV.
+ *      Richard Bean    17-May-90       Created.
+ */
+
+#include <sys/stat.h>
+
+#include <limits.h>
+
+#if !defined(_XOPEN_SOURCE)
+/*
+ * Some non-XOPEN_compilent systems are missing these definitions 
+ */
+#if !defined(SVR4)                     /* Assume BSD */
+#include <sys/param.h>
+#endif /* SVR4 */
+#endif /* !_XOPEN_SOURCE */
+
+#include <sys/time.h>
+
+#if defined(SVR4)
+#include <sys/select.h>
+#endif
+
+#include "rpc/rpc.h"
+
+#if (defined (SVR4) || defined (AIX))
+#include <netinet/in.h>
+#endif
+
+#include <netdb.h>
+
+#define SFS_MIN_RES            100             /* 100 usec resolution */
+#define        SFS_MAXNAMLEN           32              /* max test file name length */
+#define        SFS_MAXPATHLEN          1024            /* max test path name length */
+#define HOSTNAME_LEN           31              /* length of client's hostname */
+
+#include "sfs_c_nfs.h"
+
+/* --------------------------  Constants  ----------------------- */
+
+#define        SFS_VERSION_DATE        "11 July 2001"
+#define        SFS_VERSION_NUM         "3.0"
+
+/*
+ * Debugging levels
+ */
+#define        CHILD_TO_DEBUG          0       /* per child debugging uses child 0 */
+
+#define        DEBUG_NEW_CODE          (Debug_level & 0x00000001)              /* 1 */
+#define        DEBUG_PARENT_GENERAL    (Debug_level & 0x00000002)              /* 2 */
+#define        DEBUG_PARENT_SIGNAL     (Debug_level & 0x00000004)              /* 3 */
+#define        DEBUG_CHILD_ERROR       (Debug_level & 0x00000008)              /* 4 */
+#define        DEBUG_CHILD_SIGNAL      (Debug_level & 0x00000010)              /* 5 */
+#define        DEBUG_CHILD_XPOINT      (Debug_level & 0x00000020)              /* 6 */
+#define        DEBUG_CHILD_GENERAL     ((Debug_level & 0x00000040) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 7 */
+#define        DEBUG_CHILD_OPS         ((Debug_level & 0x00000080) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 8 */
+#define        DEBUG_CHILD_FILES       ((Debug_level & 0x00000100) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 9 */
+#define        DEBUG_CHILD_RPC         ((Debug_level & 0x00000200) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 10 */
+#define        DEBUG_CHILD_TIMING      ((Debug_level & 0x00000400) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 11 */
+#define        DEBUG_CHILD_SETUP       ((Debug_level & 0x00000800) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 12 */
+#define        DEBUG_CHILD_FIT         ((Debug_level & 0x00001000) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 13 */
+#define        DEBUG_CHILD_BIOD        ((Debug_level & 0x00002000) && \
+                                       (Child_num == CHILD_TO_DEBUG))  /* 14 */
+
+
+/*
+ * General constants for benchmark
+ */
+#define        DEFAULT_LOAD            60              /* calls per sec */
+#define        DEFAULT_CALLS           5000            /* number of calls */
+#define        DEFAULT_NPROCS          4               /* number of children to run */
+#define        DEFAULT_RUNTIME         (5 * 60)        /* runtime in seconds */
+#define        DEFAULT_WARMUP          (5 * 60)        /* warmup time in seconds */
+#define        DEFAULT_ACCESS          10              /* % of file set accessed */
+#define        DEFAULT_APPEND          70              /* % of writes that append */
+#define        DEFAULT_DELTA_FSS       10              /* % change to file set size */
+#define        DEFAULT_KB_PER_BLOCK    8               /* block xfer size in KB */
+#define DEFAULT_BYTES_PER_OP    (10*1024*1024)  /* bytes per unit load */
+#define        DEFAULT_NFILES          100             /* # of regular NON-IO files */
+#define        DEFAULT_FILES_PER_DIR   30              /* # of files per directories */
+#define        DEFAULT_NSYMLINKS       20              /* # of symlinks  */
+#define        DEFAULT_FAILED_LOOKUP   35              /* # of failed lookups  */
+
+#define        DEFAULT_WARM_RATE_CHECK 2               /* check progress each 2 secs */
+#define        DEFAULT_RUN_RATE_CHECK  10              /* check progress each 10 sec */
+#define        DEFAULT_MAX_BUFSIZE     NFS_MAXDATA     /* max buffer size for i/o */
+
+#define DEFAULT_BIOD_MAX_WRITE 2               /* max outstanding biod write */
+#define DEFAULT_BIOD_MAX_READ  2               /* max outstanding biod reads */
+#define MAX_BIODS              32
+
+
+/*
+ * For now we only read a fixed number of  files from a directory.  Ideally
+ * we would like to read a random number from 0-MAX but we will need a new
+ * workload.
+ */
+#define SFS_MAXDIRENTS 128
+
+/*
+ * If you change the default Chi_Sqr value,
+ * then also change the field label in the results print out.
+ */
+#define DEFAULT_CHI_SQR_CI     CHI_SQR_95      /* chi-sqr value to use */
+#define        CHI_SQR_90              2.71            /* chi-sqr value for 90% CI */
+#define        CHI_SQR_95              3.84            /* chi-sqr value for 95% CI */
+#define        CHI_SQR_975             5.02            /* chi-sqr value for 97.5% CI */
+#define        CHI_SQR_99              6.63            /* chi-sqr value for 99% CI */
+#define        CHI_SQR_995             7.88            /* chi-sqr value for 99.5% CI */
+
+/*
+ * NFS operation numbers
+ */
+#define        NULLCALL        0
+#define        GETATTR         1
+#define        SETATTR         2
+#define        ROOT            3
+#define        LOOKUP          4
+#define        READLINK        5
+#define        READ            6
+#define        WRCACHE         7
+#define        WRITE           8
+#define        CREATE          9
+#define        REMOVE          10
+#define        RENAME          11
+#define        LINK            12
+#define        SYMLINK         13
+#define        MKDIR           14
+#define        RMDIR           15
+#define        READDIR         16
+#define        FSSTAT          17
+#define ACCESS          18
+#define COMMIT          19
+#define FSINFO          20
+#define MKNOD           21
+#define PATHCONF        22
+#define READDIRPLUS     23
+#define        NOPS            (READDIRPLUS+1)         /* number of NFS ops */
+#define        TOTAL           NOPS                    /* slot for totals */
+
+/*
+ * Constants for i/o distribution table
+ */
+#define IO_DIST_START   0
+#define IO_DIST_READ    1
+#define IO_DIST_WRITE   2
+
+/*
+ * Ratio of non_io_files that are initialized
+ * NOTE: initializing half the non-i/o files works ok with the
+ *    default op mix.  If the mix is changed affecting the
+ *    ratio of creations to removes, there may not be enough
+ *    empty slots for file creation (or there may not be
+ *    enough created during initialization to handle a lot of
+ *    removes that occur early in the test run), and this would
+ *    cause do_op() to fail to find a file appropriate for the
+ *    chosen op.  This will result in the global variable
+ *    Ops[op].no_calls being incremented (turn on child level
+ *    debugging to check this count), and the do_op() local
+ *    variable aborted_ops to be incremented and checked during
+ *    runtime for too many failures.
+ */
+#define        RATIO_NON_IO_INIT 0.5
+
+/*
+ *---------------------------- TCP stuff ---------------------
+ */
+
+#define        TCPBUFSIZE      1024 * 32 + 200
+
+/* --------------------------  Macros  ----------------------- */
+
+struct ladtime {
+        uint32_t    sec;         /* seconds */
+        uint32_t    usec;        /* and microseconds */
+        uint32_t    esec;        /* seconds since standard epoch */
+};
+
+#define SUBTIME(t1, t2) { \
+       if ((t1.sec < t2.sec) || \
+               ((t1.sec == t2.sec) && (t1.usec < t2.usec))) { \
+               t1.sec = t1.usec = 0 ; \
+       } else { \
+               if (t1.usec < t2.usec) { \
+                       t1.usec += 1000000; \
+                       t1.sec--; \
+               } \
+               t1.usec -= t2.usec; \
+               t1.sec -= t2.sec; \
+       } \
+}
+
+#define        ADDTIME(t1, t2) {if ((t1.usec += t2.usec) >= 1000000) {\
+                               t1.sec += (t1.usec / 1000000); \
+                               t1.usec %= 1000000; \
+                        } \
+                        t1.sec += t2.sec; \
+                       }
+
+#define MINIMUM(a, b) ((a < b) ? (a) : (b))
+#define MAXIMUM(a, b) ((a > b) ? (a) : (b))
+
+#define MULTIME(t1, s) { \
+       t1.usec *=s; \
+       t1.sec *=s; \
+       if (t1.usec >= 1000000) {\
+               t1.sec += (t1.usec/1000000); \
+               t1.usec %= 1000000; \
+       }\
+       }
+#define DIVTIME(t1, s) { \
+       t1.usec += (t1.sec % s ) *1000000; \
+       t1.sec /= s; \
+       t1.usec /= s; \
+       }
+#define LARGERTIME(t1, t2) \
+ ((t1.sec>t2.sec) || ((t1.sec==t2.sec) && (t1.usec>t2.usec))) 
+
+/* --------------------------  Types  ----------------------- */
+
+/*
+ * SFS test phases.  Values are well-ordered for use of "<" operations.
+ */
+#define        Mount_phase      1  /* test directories are being mounted */
+#define        Populate_phase   2  /* files being created in the test directories */
+#define        Warmup_phase     3  /* reach steady state (load is being generated) */
+#define        Testrun_phase    4  /* timed test run (load is being generated) */
+#define        Results_phase    5  /* results collection and reporting */
+typedef int sfs_phase_type;
+
+/*
+ * Index constants for lookups into the RPC timer array.
+ */
+#define        Init    0
+#define        Lookup  1
+#define        Read    2
+#define        Write   3
+
+/*
+ * SFS results information structure
+ */
+typedef struct {
+       int             good_calls;     /* successful calls */
+       int             bad_calls;      /* failed (timed out) calls */
+       int     timeout_calls;  /* RFS timeout calls */
+       int             fast_calls;     /* calls that competed in 0 time */
+       struct ladtime  time;           /* cumulative execution time */
+       double          msec2;          /* cumulative squared time - msecs**2 */
+} sfs_results_type;
+
+/*
+ * SFS information reported from child back to parent.
+ */
+typedef struct {
+       int                     version;
+       sfs_results_type        results_buf[NOPS+1];
+       int                     total_fss_bytes;
+       int                     least_fss_bytes;
+       int                     most_fss_bytes;
+       int                     base_fss_bytes;
+} sfs_results_report_type;
+
+
+/*
+ * SFS operation information structure
+ */
+
+typedef struct {
+       char *          name;           /* operation name */
+       int             mix_pcnt;       /* percentage of call target */
+#ifndef RFS
+       int             (*funct)();     /* op routine */
+#endif
+       int             call_class;     /* call class: client handle & timeo */
+       int             target_calls;   /* number of calls to make */
+       int             no_calls;       /* # of times a call couldn't be made */
+       double          req_pcnt;       /* cumulative request percentile */
+       int             req_cnt;        /* number of requests made */
+       int             target_reqs;    /* number of req to be made */
+       sfs_results_type results;       /* test results */
+} sfs_op_type;
+
+
+/*
+ * Flags used with randfh
+ */
+#define RANDFH_TRUNC           0x01    /* pick a file to truncate */
+#define RANDFH_APPEND          0x02    /* pick a file to append to */
+
+/*
+ * SFS file information structure
+ * The particular values assiged are used to perform mod operations.
+ */
+#define        Sfs_io_file             0       /* read, write ops only (0) */
+#define        Sfs_non_io_file         1       /* other regular file ops only (1) */
+#define        Sfs_symlink             2       /* symlink ops only (2) */
+#define        Sfs_dir                 3       /* dir ops only (3) */
+#define        Sfs_regular             4       /* any regular file (0,1) */
+#define        Sfs_non_dir             5       /* any non-directory file (0,1,2) */
+#define        Sfs_any_file            6       /* any file, link, or dir (0,1,2,3) */
+typedef int sfs_file_type;
+
+#define        Exists          1       /* op needs an object that already exists */
+#define        Nonexistent     2       /* op will create an object */
+#define        Empty_dir       3       /* op needs an empty directory */
+typedef char sfs_state_type;
+
+/*
+ * One file (dir, or symlink) in the file set.
+ */
+typedef struct sfs_fh_data {
+       union {
+               fhandle_t       f_fh2;            /* the NFS V2 file handle */
+               nfs_fh3         f_fh3;            /* the NFS V3 file handle */
+       } sfs_fh_un;
+       union {
+               fattr           a_attributes2;    /* its V2 attributes */
+               fattr3          a_attributes3;    /* its V3 attributes */
+       } sfs_fattr_un;
+       char                    file_name[SFS_MAXNAMLEN]; /* path component*/
+} sfs_fh_data;
+
+typedef struct sfs_fh_type {
+       struct sfs_fh_type      *dir;           /* Parent Directory */
+       struct sfs_fh_data      *fh_data;       /* Data area */
+       int                     size;           /* its size */
+       int                     unique_num;     /* unique part of filename */
+       int                     use_cnt;        /* count of op to this file */
+       int                     xfer_cnt;       /* count of KB xfered */
+       sfs_state_type          state;          /* existence state */
+       char                    working_set;    /* is in the working set */
+       char                    initialize;     /* should be initialized */
+#define        attributes2     fh_data->sfs_fattr_un.a_attributes2
+#define        attributes3     fh_data->sfs_fattr_un.a_attributes3
+#define        fh2     fh_data->sfs_fh_un.f_fh2
+#define        fh3     fh_data->sfs_fh_un.f_fh3
+#define        file_name       fh_data->file_name
+} sfs_fh_type;
+
+#define fh_size(fhptr) (nfs_version == NFS_VERSION ? \
+                                               (fhptr)->attributes2.size : \
+                                               (fhptr)->attributes3.size._p._l)
+
+#define fh_uid(fhptr)  (nfs_version == NFS_VERSION ? \
+                               (uint32_t)((fhptr)->attributes2.uid) : \
+                               (uint32_t)((fhptr)->attributes3.uid))
+
+#define fh_gid(fhptr)  (nfs_version == NFS_VERSION ? \
+                               (uint32_t)((fhptr)->attributes2.gid) : \
+                               (uint32_t)((fhptr)->attributes3.gid))
+
+#define fh_mode(fhptr) (nfs_version == NFS_VERSION ? \
+                               (uint32_t)((fhptr)->attributes2.mode) : \
+                               (uint32_t)((fhptr)->attributes3.mode))
+
+#define fh_isdir(fhptr)        (nfs_version == NFS_VERSION ? \
+                               ((fhptr)->attributes2.type == NFDIR) : \
+                               ((fhptr)->attributes3.type == NF3DIR))
+
+#define fh_isfile(fhptr) (nfs_version == NFS_VERSION ? \
+                               ((fhptr)->attributes2.type == NFREG) : \
+                               ((fhptr)->attributes3.type == NF3REG))
+
+/*
+ * One file (dir, or symlink) in the working file set.
+ */
+typedef struct {
+       int             range;          /* random access range for this file */
+       int             index;          /* points into actual file array */
+} sfs_work_fh_type;
+
+typedef struct {
+       sfs_work_fh_type        *entries;          /* array of working files */
+       int                     access_group_size; /* # files in a group */
+       int                     access_group_cnt;  /* # groups in workset */
+       int                     max_range;         /* access range of workset */
+} sfs_work_set_type;
+
+
+
+/*
+ * SFS file size distribution structures
+ */
+typedef struct {
+       int             pcnt;           /* percentile */
+       int             bufs;           /* Block_size KB xfers */
+       int             frags;          /* boolean - is a frag present */
+} sfs_io_op_dist_type;
+
+typedef        struct {
+       sfs_io_op_dist_type     *read;          /* read size table */
+       sfs_io_op_dist_type     *write;         /* write size table */
+       int                     max_bufs;       /* max # of Block_size xfers */
+       double          avg_ops_per_read_req;   /* avg read ops/req */
+       double          avg_ops_per_write_req;  /* avg write ops/req */
+} sfs_io_dist_type;
+
+typedef struct {
+       int             pcnt;           /* percentile */
+       int             size;           /* file size in KB */
+} sfs_io_file_size_dist;
+
+
+/* sfs child processes synchronization logfile */
+#define        CHILD_SYNC_LOG  "/tmp/sfs_log"
+#define        SFS_PNT_PID     "/tmp/sfs_pnt_pid"
+#define        SFS_PRM_PID     "/tmp/sfs_prm_pid"
+#define        SFS_SYNCD_PID   "/tmp/sfs_syncd_pid"
+
+/*
+ * Values for invalid runs
+ */
+#define INVALID_UNKNOWN                1       /* Old value reserved as unknown */
+#define INVALID_IODIST         2
+#define INVALID_MIX            3
+#define INVALID_RUNTIME                4
+#define INVALID_ACCESS         5
+#define INVALID_APPEND         6
+#define INVALID_KB             7
+#define INVALID_NDIRS          8
+#define INVALID_FSS            9
+#define INVALID_BIODREAD       10
+#define INVALID_NSYMLINKS      11
+#define INVALID_BIODWRITE      12
+#define INVALID_WARMUP         13
+#define INVALID_GOODCALLS      14
+#define INVALID_FAILEDRPC      15
+#define INVALID_NOTMIX         16
+#define INVALID_MAX            (INVALID_NOTMIX + 1)
+
+/*
+ * External variable declarations
+ */
+extern int             Access_percent;
+extern int             Append_percent;
+extern int             Base_fss_bytes;
+extern int             Biod_max_outstanding_reads;
+extern int             Biod_max_outstanding_writes;
+extern int             Bytes_per_block;
+extern int             Child_num;
+extern int             Client_num;
+extern sfs_fh_type     *Cur_file_ptr;
+extern char            Cur_filename[];
+extern gid_t           Cur_gid;
+extern struct ladtime  Cur_time;
+extern uid_t           Cur_uid;
+extern sfs_phase_type  Current_test_phase;
+extern int             Debug_level;
+extern sfs_io_file_size_dist Default_file_size_dist[];
+extern sfs_fh_type     *Dirs;
+extern uint32_t                Dump_count;
+extern int             dump_create_existing_file;
+extern int             Dump_data;
+extern uint32_t                Dump_length;
+extern uint32_t                Dump_offset;
+extern int             dump_truncate_op;
+extern sfs_fh_type     Export_dir;
+extern char            Filespec[];
+extern char            Dirspec[];
+extern char            Symspec[];
+extern int             avg_bytes_per_file;
+extern int             files_per_megabyte;
+extern int             Fss_delta_percent;
+extern int             Interactive;
+extern sfs_io_dist_type * Io_dist_ptr;
+extern sfs_fh_type     *Io_files;
+extern int             Kb_per_block;
+extern char *          sfs_Myname;
+extern int             Least_fss_bytes;
+extern int             Limit_fss_bytes;
+extern int             Cur_fss_bytes;
+extern int             Total_fss_bytes;
+extern int             Log_fd;
+extern char            Logname[];
+extern int             Most_fss_bytes;
+extern int             Msec_per_period;
+extern CLIENT *                NFS_client;
+extern CLIENT *                NFS_client_recv;
+extern struct timeval  *Nfs_timers;
+extern struct timeval  Nfs_udp_timers[];
+extern struct timeval  Nfs_tcp_timers[];
+extern int             nfs_version;
+extern sfs_fh_type     *Non_io_files;
+extern int             Num_dirs;
+extern int             Num_dir_files;
+extern int             Num_failed_lookup;
+extern int             Num_io_files;
+extern int             Num_non_io_files;
+extern int             Num_symlinks;
+extern int             Num_symlink_files;
+extern int             Num_working_dirs;
+extern int             Num_working_io_files;
+extern int             Num_working_non_io_files;
+extern int             Num_working_symlinks;
+extern sfs_op_type     *Ops;
+extern int             Populate_only;
+extern char *          Prime_client;
+extern uid_t           Real_uid;
+extern int             Runtime;
+extern struct ladtime  Starttime;
+extern int             start_run_phase;
+extern sfs_fh_type     *Symlinks;
+extern int             Tcp;
+extern int             Testop;
+extern int             Files_per_dir;
+extern int             Tot_client_num_io_files;
+extern int             Tot_client_num_non_io_files;
+extern int             Tot_client_num_symlinks;
+extern int             Timed_run;
+extern int             Validate;
+extern int             Warmuptime;
+extern char            *invalid_str[];
+extern char            lad_hostname[];
+
+
+/*
+ * External function declarations
+ */
+extern int     biod_init(int, int);
+extern void    biod_term(void);
+extern void    biod_turn_on(void);
+extern int     check_access(struct stat *);
+extern int     check_fh_access(sfs_fh_type *);
+extern void    child(int, int, float, int, char **);
+extern void    generic_catcher(int);
+extern int     generic_kill(int, int);
+extern void    init_counters(void);
+extern void    init_fileinfo(void);
+extern void    init_mount_point(int, char *, CLIENT *);
+extern void    init_ops(void);
+extern char *  init_write_buffer(void);
+extern CLIENT * lad_getmnt_hand(char *);
+extern CLIENT *        lad_clnt_create(int, struct hostent *, uint32_t,
+                       uint32_t, int, struct timeval *);
+extern char *  lad_timestamp(void);
+extern int     set_debug_level(char *s);
+extern void    sfs_alarm(int);
+extern void    sfs_cleanup(int);
+extern void    sfs_elapsedtime(sfs_op_type *, struct ladtime *,
+                                struct ladtime *);
+extern void    sfs_gettime(struct ladtime  *);
+extern int32_t sfs_random(void);
+extern void    sfs_srandom(int);
+extern int     init_rand_range(int);
+extern int     rand_range(int);
+extern void    sfs_startup(int);
+extern void    sfs_stop(int);
+extern void    log_dump(struct ladtime *, struct ladtime *, int);
+extern void    parent(int, int, char *, char *);
+extern void    print_dump(int, int);
+extern sfs_fh_type *
+               randfh(int, int, uint_t, sfs_state_type, sfs_file_type);
+extern int     msec_sleep(int);
+extern void    Validate_ops(int, char **);
+
+/* Reliable RPC functions for initialization */
+extern int     lad_lookup(sfs_fh_type *, char *);
+extern int     lad_remove(sfs_fh_type *, char *);
+extern int     lad_rmdir(sfs_fh_type *, char *);
+extern int     lad_symlink(sfs_fh_type *, char *, char *);
+extern int     lad_mkdir(sfs_fh_type *, char *);
+extern int     lad_write(sfs_fh_type *, int32_t, int32_t);
+extern int     lad_create(sfs_fh_type *, char *);
+extern int     lad_truncate(sfs_fh_type *, int32_t);
+
+/* RFS: moved the definition from sfs_c_bio.c to here because it is used in 
+ * sfs_c_chd.c in the new code, information associated with outstanding requests
+ */
+struct biod_req {
+    uint32_t           xid;            /* RPC transmission ID  */
+    bool_t             in_use;         /* Indicates if the entry is in use */
+       int     dep_tab_index;                  /* corresponding index in dep_tab */
+    unsigned int       count;          /* Count saved for Dump routines */
+    unsigned int       offset;         /* Offset saved for Dump routines */
+    struct ladtime     start;          /* Time RPC call was made */
+    struct ladtime     stop;           /* Time RPC reply was received */
+    struct ladtime     timeout;        /* Time RPC call will time out */
+};
+
+#endif /* sfs_def.h */
diff --git a/TBBT/trace_play/sfs_c_dmp.c b/TBBT/trace_play/sfs_c_dmp.c
new file mode 100644 (file)
index 0000000..82d9a38
--- /dev/null
@@ -0,0 +1,298 @@
+#ifndef lint
+static char sfs_c_dmpSid[] = "@(#)sfs_c_dmp.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_dmp.c ---------------------
+ *
+ *      Raw data dump routines for SFS.
+ *
+ *     The routines contained here capture and dump the raw data
+ *     points (operation, response time) to allow the researcher
+ *     to perform detailed analysis on the response time characteristics
+ *     of an NFS server.
+ *
+ *.Exported Routines
+ *     void log_dump(ladtime *, ladtime *, int)
+ *     void print_dump(int, int)
+ *
+ *.Local Routines
+ *     None.
+ *
+ *.Revision_History
+ *     11-Jul-94       ChakChung Ng    Add codes for NFS/v3
+ *     03-Feb-92       0.0.20 Pawlowski
+ *                                     Use of "Current_test_phase"
+ *                                     obviates need for dump init
+ *                                     routine, so it has been deleted.
+ *     10-Jan-92       0.0.19 Teelucksingh
+ *                                     Changed dump file names to be
+ *                                     < 14 chars. Added header to
+ *                                     output.
+ *      04-Jan-92      0.0.18 Pawlowski
+ *                                     Added raw data dump code.
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+
+struct savedata {
+    struct savedata    *next;
+    int32_t    rtv_sec;        /* The response time */
+    int32_t    rtv_usec;
+    int32_t    stv_sec;        /* The start time */
+    int32_t    stv_usec;
+    uint32_t   count;          /* Used only for read and write */
+    uint32_t   offset;         /* Used only for read and write */
+    uint32_t   length;         /* Used only for read and write */
+    uint16_t   unique_num;     /* unique id for file */
+    unsigned int flags;                /* Things like whether truncating, etc. */
+    int16_t    op;
+};
+
+uint32_t       Dump_count;     /* place to put read and write count */
+uint32_t       Dump_offset;    /* place to put r/w offset */
+uint32_t       Dump_length;    /* place to put r/w offset */
+int            Dump_data;      /* Flag set by command line option */
+int            dump_create_existing_file = FALSE;
+int            dump_truncate_op = FALSE;
+
+/*
+ * ----------------------  Static Declarations  ----------------------
+ */
+
+static struct savedata *saveary = 0;
+
+/*
+ * --------------------------  Constants  --------------------------
+ */
+
+/* flags bit values */
+#define CREATE_OF_EXISTING_FILE        0x0001
+#define TRUNCATE_OPERATION     0x0002
+
+/*
+ * ----------------------  Dump Routines  ----------------------
+ */
+
+/*
+ * log_dump()
+ *
+ * This function is called on the completion of every operation
+ * to log the data point. We log the operation and the elapsed time
+ * (storing the microsecond component also).
+ *
+ * The data is kept in a singly linked list, elements dynamically
+ * allocated as needed.
+ *
+ * Dynamic allocation of elements using malloc and single link list
+ * pointer adds overhead to the storage space for the data for each
+ * point. Dynamic allocation can result in system calls to get more
+ * space for elements, adding to execution overhead. However, if you're
+ * doing a raw data dump run, you assume costs are negligible.
+ */
+
+void
+log_dump(
+    struct ladtime *start,
+    struct ladtime *elapsed,
+    int op)
+{
+    static struct savedata *saveptr = 0;
+
+    if (!Dump_data || Current_test_phase != Testrun_phase)
+       return;
+
+    if (saveary == (struct savedata *)NULL) {
+       if ((saveary = (struct savedata *)
+                       malloc(sizeof(struct savedata)))
+                               == (struct savedata *)NULL) {
+           (void) fprintf(stderr, "Unable to allocate dump element\n");
+           return;
+       }
+       saveptr = saveary;
+    } else {
+       if ((saveptr->next = (struct savedata *)
+                       malloc(sizeof(struct savedata)))
+                               == (struct savedata *)NULL) {
+           (void) fprintf(stderr, "Unable to allocate dump element\n");
+           return;
+       }
+       saveptr = saveptr->next;
+    }
+    saveptr->next = (struct savedata *)NULL;
+    saveptr->flags = 0;
+    saveptr->op = op;
+    saveptr->rtv_sec = elapsed->sec;
+    saveptr->rtv_usec = elapsed->usec;
+    saveptr->stv_sec = start->sec;
+    saveptr->stv_usec = start->usec;
+    saveptr->unique_num = Cur_file_ptr->unique_num;
+    if (op == NFSPROC3_READ || op == NFSPROC3_WRITE ||
+       op == NFSPROC_READ || op == NFSPROC_WRITE) {
+       saveptr->count = (uint16_t) Dump_count;
+       saveptr->offset = Dump_offset;
+       saveptr->length = Dump_length;
+    }
+
+    if (dump_create_existing_file == TRUE) {
+       saveptr->flags |= CREATE_OF_EXISTING_FILE;
+       dump_create_existing_file = FALSE;
+    }
+
+    if (dump_truncate_op == TRUE) {
+       saveptr->flags |= TRUNCATE_OPERATION;
+       dump_truncate_op = FALSE;
+    }
+}
+
+/*
+ * print_dump()
+ *
+ * Dumps the raw data to a file in the format:
+ *
+ *     opcode  sec.msec  sec.msec file-unique-id <length> <offset> <count>
+ *     opcode  sec.msec  sec.msec file-unique-id
+ *          . . .
+ *
+ * The opcode is the numeric NFS operation code as defined in the
+ * NFS protocol specification. The first "sec.msec" field is the
+ * response time of the operation. The second "sec.msec" field
+ * is the start time of the operation. For read and write calls,
+ * the "length", "offset" and "count" from the operation arguments are put out
+ * as the fourth, fifth, and sixth field.
+ *
+ * This simple (x, y) pairing should be suitable input for a wide variety
+ * of plotting programs.
+ *
+ * Note that the raw data is precious! Several points to be observed:
+ *
+ *     1. The raw data for each individual child is dumped to
+ *        its own data file. So each individual child process
+ *        data can be inspected (possibly useful to debug client
+ *        load generation per child process anomalies).
+ *
+ *     2. More importantly, each raw data dump file presents
+ *        the operations generated by the child in their exact
+ *        order of generation. This can be used to analyze possible
+ *        time dependent behaviour of the server.
+ *
+ * Client process output files can be merged for analysis using cat(1).
+ *
+ * If any other data (additional fields) are added to raw data dump
+ * file, please add those fields after primary fields. awk(1) scripts
+ * and the like can be used to re-arrange data files, but it would
+ * be nice if the primary (x, y) data points are the default format.
+ */
+
+void
+print_dump(
+    int clientnum,
+    int childnum)
+{
+    char buf[256];
+    FILE *datap;
+    struct savedata *p = saveary;
+
+    buf[0] = 0;
+
+    if (!Dump_data)
+       return;
+
+    /*
+     * We write raw data files to the /tmp directory, and
+     * the manager will retrieve to the prime client.
+     *
+     * Removed preladraw prefix from file names to fit
+     * in 14 chars - K.T.
+     */
+
+    (void) sprintf(buf, "/tmp/c%3.3d-p%3.3d", clientnum, childnum);
+
+    if ((datap = fopen(buf, "w")) == NULL) {
+       (void) fprintf(stderr, "couldn't open %s for writing\n", buf);
+       return;
+    }
+
+    (void) fprintf(datap,"%s\n%s\n%s\n%s\n",
+"-----------------------------------------------------------------------------",
+"         Op Response           Start         Unique  File",
+"       Code     Time            Time        File Id  Length  Offset  Size",
+"-----------------------------------------------------------------------------");
+
+    p = saveary;
+    while(p) {
+       (void) fprintf(datap, "%11s %8.3f %19.3f %8d",
+               Ops[p->op].name,
+               (p->rtv_sec * 1000.0) + (p->rtv_usec / 1000.0),
+               (p->stv_sec * 1000.0) + (p->stv_usec / 1000.0),
+               p->unique_num);
+       if (p->op == NFSPROC3_READ || p->op == NFSPROC3_WRITE ||
+               p->op == NFSPROC_READ || p->op == NFSPROC_WRITE) {
+           (void) fprintf(datap,
+               " %8d %8d %5d\n", p->length, p->offset, p->count);
+       }
+       else if (p->op == NFSPROC3_SETATTR || p->op == NFSPROC3_CREATE ||
+               p->op == NFSPROC_SETATTR || p->op == NFSPROC_CREATE) {
+           if (p->flags & TRUNCATE_OPERATION) {
+               (void) fprintf(datap, "  %s", "TRUNCATE");
+           }
+           if (p->flags & CREATE_OF_EXISTING_FILE) {
+               (void) fprintf(datap, "  %s", "CREATE_EXISTING");
+           }
+           (void) fprintf(datap, "\n");
+       }
+       else {
+               (void) fprintf(datap, "\n");
+       }
+       p = p->next;
+    }
+
+    (void) fprintf(datap,
+"-----------------------------------------------------------------------------\n\n");
+    (void) fclose(datap);
+}
diff --git a/TBBT/trace_play/sfs_c_man.c b/TBBT/trace_play/sfs_c_man.c
new file mode 100644 (file)
index 0000000..33bf28a
--- /dev/null
@@ -0,0 +1,1998 @@
+#ifndef lint
+static char sccsid_hp[] = "@(#)sfs_c_man.c     2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*
+ * Generates an artifical NFS client load based on a given mix of operations,
+ * and block transfer distribution.
+ *
+ * Usage: sfs [-l load] [-p procs] [-w warmup] [-t time]
+ *               [-m mix_file] [-B block_size] [-b blocksz_file]
+ *              [-f file_set_delta] [-a access_pnct]
+ *              [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]
+ *              [-d debug_level] [-i] [-P] [-T op_num]
+ *              [-V validation_level] [-z] [-Q]
+ *              [-R biod_reads] [-W biod_writes]
+ *              [-M prime_client_hostname] [-N client_cnt]
+ *
+ * NOTE: REFER TO SFS MAN PAGE (sfs.1) FOR A DESCRIPTION OF ALL
+ *      SFS OPTIONS
+ *
+ *
+ * Single Client Options
+ *
+ * option         description                                      default
+ * --------------- ------------------------------------------------ -----------
+ * -a access_pcnt  % of file set to access                         20% access
+ * -A append_pcnt  % of writes that append rather than overwrite    70% append
+ * -b blocksz_file file specifying distribution of block xfer sizes (see below)
+ * -B block_size   # of KB in block, up to 8 KB                            8 KB
+ * -Q              Do TCP connection for NFS rather than UDP        off
+ * -d debug_level  debug level (higher number gives more output)    off
+ * -D dir_cnt     # directories used for directory operations      20 dirs
+ * -f fileset_delta % change in file set size allowed               10%
+ * -F file_cnt    # files used for read and write operations       100 files
+ * -i             interactive; wait for input before starting test off
+ * -l load        # NFS calls/second to generate from each client  60 calls/sec
+ * -m mix_file    file specifying NFS call distribution            (see below)
+ * -p procs       # processes used to generate load on each client 7 procs
+ * -P             populate test directories, but don't run a test  off
+ * -R biod_reads   max # of outstanding read requests at one time   2 reqs
+ * -S symlink_cnt  # symbolic links used for symlink operations     20 symlinks
+ * -t time        # seconds to generate load for the timed test    600 secs
+ * -T op_num      test the NFS operation specified one time        off
+ * -V             validate correctness of server's NFS             off
+ * -W biod_writes   max # of outstanding writes req at one time     2 reqs
+ * -w warmup      # secs to generate load before starting test     60 secs
+ * -z             If specified, collect and dump raw data.         off
+ *
+ *
+ * Multi Client Options
+ *
+ * option                      description                         default
+ * ------------------------     ----------------------------------- -----------
+ * -M prime_client_hostname    hostname of prime client            no default
+ * -N client_cnt               # client machines in test           no default
+ *
+ *
+ *
+ * Block Transfer Size Distribution
+ *
+ * The block transfer size distribution is specified by a table of values.
+ * The first column gives the percent of operations that will be a
+ * specific block transfer size.  The second column gives the number of
+ * blocks units that will be transferred.  Normally the block unit size
+ * is 8KB.  The third column is a boolean specifying whether a trailing
+ * fragment block should be transferred.  The fragment size for each transfer
+ * is a random multiple of 1 KB, up to the block size - 1 KB.  Two tables
+ * are needed, one for read operation and one for write operations.  The
+ * following table gives the default distributions.
+ *
+ *     Read  - Default Block Transfer Size Distribution Table
+ * percent   block count   fragment    resulting transfer (8KB block size)
+ * -------   -----------   --------    -----------------------------------
+ *    0        0             0                  0%    1 -   7 KB
+ *   85        1             0                 85%    9 -  15 KB
+ *    8        2             1                  8%   17 -  23 KB
+ *    4        4             1                  4%   33 -  39 KB
+ *    2        8             1                  2%   65 -  71 KB
+ *    1       16             1                  1%  129 - 135 KB
+ *
+ *     Write  - Default Block Transfer Size Distribution Table
+ * percent   block count   fragment    resulting transfer (8KB block size)
+ * -------   -----------   --------    -----------------------------------
+ *   49        0             1         49%    1 -   7 KB
+ *   36        1             1         36%    9 -  15 KB
+ *    8        2             1           8%   17 -  23 KB
+ *    4        4             1          4%   33 -  39 KB
+ *    2        8             1          2%   65 -  71 KB
+ *    1       16             1          1%  129 - 135 KB
+ *
+ * The user may specify a a different distribution by using the '-b' option.
+ * The format for the block size distribution file consists of the first
+ * three columns given above: percent, block count, and fragment.  Read
+ * and write distribution tables are identified by the keywords "Read" and
+ * "Write".  An example input file, using the default values, is given below:
+ *
+ *             Read
+ *              0  0  0
+ *             85  1  0
+ *              8  2  1
+ *              4  4  1
+ *              2  8  1
+ *              1 16  1
+ *             Write
+ *             49  0  1
+ *             36  1  1
+ *              8  2  1
+ *              4  4  1
+ *               2  8  1
+ *               1 16  1
+ *
+ * A second parameter controlled by the block transfer size distribution
+ * table is ethernet packet size.  The distribution tables define the
+ * relative proportion of full blocks packets to fragment packets.  For
+ * instance, the default tables have been constructed to produce a specific
+ * distribution of ethernet packet sizes for i/o operations by controlling
+ * the amount of data in each packet.  The write packets produced consist
+ * of 50% 8-KB packets, and 50% 1-7 KB packets.  The read packets consist
+ * of 85% 8-KB packets, and 15% 1-7 KB packets.  These figures are
+ * determined by multiplying the percentage for the type of transfer by
+ * the number of blocks and fragments generated, and adding the totals.
+ * These conmputations are performed below for the default block size
+ * distribution tables:
+ *
+ *             Read            blocks          fragments
+ *              0  0  0          0               0
+ *             85  1  0         85               0
+ *              8  2  1         16               8
+ *              4  4  1         16               4
+ *              2  8  1         16               2
+ *              1 16  1         16               1
+ *                             ---             ---
+ *                             149 (90%)        15 (10%)
+ *
+ *             Write
+ *             49  0  1          0              49
+ *             36  1  1         36              36
+ *              8  2  1         16               8
+ *              4  4  1         16               4
+ *               2  8  1        16               2
+ *               1 16  1        16               1
+ *                             ---             ---
+ *                             100 (50%)       100 (50%)
+ *
+ *
+ *
+ *
+ *
+ * NFS Operation Mix
+ *
+ * The operation mix is described assigning a percentage to each type
+ * of NFS operation.  The default mix of operations is:
+ *
+ * operation   percent
+ * ---------   -------
+ * null                 0
+ * getattr     13
+ * setattr      1
+ * root                 0
+ * lookup      34
+ * readlink     8
+ * read                22
+ * wrcache      0
+ * write       15
+ * create       2
+ * remove       1
+ * rename       0
+ * link                 0
+ * symlink      0
+ * mkdir        0
+ * rmdir        0
+ * readdir      3
+ * fsstat       1
+ *
+ * The user may specify a a different operation mix by using the '-m' option.
+ * The format for the mix file consists of the output from an nfsstat(1)
+ * command, which lists an operation count and percentage for each NFS
+ * operation.
+ *
+ *
+ * File Set Size
+ *
+ * !!! needs to be re-written - mew 8/24
+ * This still needs to be rewritten
+ *   - The default number of i/o files is based on load level.
+ *   - For non I/O files, the number of initialized versus empty
+ *     slots is hardcoded
+ *  - dr 2/8/94
+ *
+ * The file set used by SFS is determined by 2 factors. First,
+ * SFS creates a base set of files.  By default this consists of
+ * 100 files for i/o operations, 100 files for non-i/o operations, 20
+ * directories, and 20 symbolic links.  These default values can be
+ * changed from the command line by using the "-F", "-D", and "-S" options.
+ * This file set is divided evenly among the set of processes used to
+ * generate load.
+ *
+ * Then, enough resources are allocated to allow for the eventual creation
+ * of new files, directories and symlinks by the creat, link, mkdir,
+ * and symlink operations.  The number of extra slots allocated depends
+ * on the mix percentages assigned to each of the create and deletion
+ * operations, multiplied by an estimate of the total number of operations
+ * to be performed.  For instance, the default number of extra files names
+ * allocated for non-i/o operations is computed as follows:
+ *     300 secs * 60 ops/sec = 18000 total operations
+ *     2% create * 18000 ops = 360 create ops
+ *     1% remove * 18000 ops = 180 remove ops
+ *     260 creates ops - 180 remove ops = 180 extra files to be created.
+ * These 90 files are distributed evenly among the processes used to
+ * generate load.  With the default settings, no extra directories are
+ * created or removed, so no extra allocation is done for directories
+ * beyond the base file set.  The same is true for symbolic links.
+ *
+ * Thus, the total default file set size is:
+ *     100 files for i/o operations
+ *     280 files for non-i/o operations
+ *      20 directories
+ *      20 symlinks
+ *
+ * By allocating all required space before the test begins, any space
+ * allocation problems encountered by SFS are discovered before the
+ * test is started.
+ *
+ *
+ * Program Control
+ *
+ * Strategy: loop for some number of NFS calls doing a random sleep
+ * followed by a call to one of the op generator routines. The routines
+ * are called based on a weighting factor determined by the set of
+ * default percentages or a mix supplied by the user.
+ *
+ * The generator routines are able to keep an accurate count of the
+ * NFS operations they are generating by using the NFS protocol
+ * directly and not going through the kernel.  This eliminates the
+ * effects of kernel name caches and retry mechanisms that
+ * complicate control of what actually hits the wire.  The calling
+ * routine benefits by avoiding having to get the NFS statistics
+ * from the kernel because they KNOW what calls they've made.
+ *
+ * By using the NFS protocol directly :
+ *     "lookup" operations sidestep the client kernel name cache,
+ *     "getattr" operations avoid the client kernel attribute cache,
+ *     "read" operations avoid the client kernel buffer cache,
+ *     and so on.
+ *
+ * A consequence of not going thru the client kernel is that the sfs
+ * program must maintain a table of file handles rather than open
+ * file descriptors.
+ *
+ * The parent process starts children to do the real work of generating load.
+ * The parent coordinates them so that they all start at the same time, and
+ * collects statistics from them when they are done. To coordinate the
+ * start up, the parent waits for each child to write one byte into
+ * a common log file (opened in append mode to avoid overwriting).
+ * After they write a byte the children pause, and the parent send SIGUSR1
+ * when it has heard from all of the kids. The children write their statistics
+ * into the same common log file and the parent reads and accumulates the
+ * statistics and prints them out.
+ *
+ *
+ *.Exported_Routines
+ *     int main(int, char*)
+ *
+ *.Local_Routines
+ *     void init_logfile(void)
+ *     void usage(void)
+ *     int setmix(char *)
+ *     int setiodist(FILE *)
+ *     int parseiodist(FILE *, int)
+ *     void init_iodist(sfs_io_dist_type *)
+ *     void init_fss(void)
+ *     void init_filedist(void)
+ *     int lad_substr(char *, char *)
+ *
+ *.Revision_History
+ *     21-Aug-92       0.1.11   Wittle File set access code.
+ *      14-Jul-92      0.1.9    Teelucksingh
+ *                                     Implemented Mark Wittle's proposal to
+ *                                     base File Set Size on peak load value,
+ *                                     added "-L peak_load" option.
+ *     10-Jan-92       0.0.0.19 Teelucksingh
+ *                                     Reworked setpgrp() usage to
+ *                                     better handle BSD vs SYSV variations.
+ *      04-Jan-92       0.0.0.18 Pawlowski
+ *                                      Added raw data dump code.
+ *      04-Dec-91      0.0.0.15 Keith
+ *                                     Include string.h if SVR4.
+ *     28-Nov-91       0.0.0.13 Teelucksingh
+ *                                     Modified code to use unique sfs /tmp
+ *                                     logfiles; sfs can now be used on
+ *                                     clients that have a shared /tmp area.
+ *                                     Added ANSI C features. Fixed 'multiple
+ *                                     signals from the Prime-Client' problem.
+ *                                     Added code to allow clients to
+ *                                     check for and create client specific
+ *                                     directories under each mount point -
+ *                                     clients share partitions. (code from
+ *                                     M.Molloy).
+ *     22-Nov-91                Wittle Updated program description comment.
+ *                                     Added new op generation code.
+ *                                     Added block_dist_table and block_size
+ *                                     options, removed 8KB packet assumptions.
+ *     04-Oct-91       0.0.0.12 Teelucksingh
+ *                                     Changed SFS sources and executables
+ *                                     to use the "prelad" prefix.
+ *     23-Sep-91       0.0.0.11 Teelucksingh
+ *                                     Changed format of sfs output.
+ *     01-Aug-91       0.0.9 Wiryaman  Use the SPEC random number generator.
+ *                                     Since this RNG cannot take seed = 0,
+ *                                     use child_num+1 instead.
+ *     17-Jul-91       0.0.8 Teelucksingh
+ *                                     Enhance multi-client code and
+ *                                     documentation.
+ *                           Keith     Map "nhfsstone" to "laddis" in
+ *                                     README, nhfsstone_mgr.c. Create
+ *                                     initial DESCR.SFS for SPEC
+ *                                     submission.
+ *     15-Jul-91       0.0.8 Wiryaman  Add getmnt() for ULTRIX
+ *     25-Jun-91       0.0.7 Wiryaman  Added validation option to test all
+ *                                     of the NFS operations.
+ *     17-Jun-91       0.0.7 Teelucksingh
+ *                                     Added multi-client synchronization
+ *                                     support. By designating a client as
+ *                                     "Prime client" you can synchronize
+ *                                     multi-client SFS execution.
+ *     12-May-91       0.0.6 Wittle    Fix standard deviation.
+ *     02-May-91       0.0.5 Wittle    Fix SunOS signal bug; use default
+ *                                     warmuptime; add local time routine;
+ *                                     check for calls that underflow elapsed
+ *                                     time measurement; add std deviation
+ *                                     statistics; rework verbose output.
+ *                                     fix init invalid protocol rmdir calls;
+ *     15-Apr-91       0.0.4 Wittle    Test can be repeated without removing
+ *                                     test directories - initialization
+ *                                     restores base file set count and sizes.
+ *                                     Fix lack of call rate & mix accuracy -
+ *                                     set op_check before artificially
+ *                                     increasing call_targets.
+ *                                     Don't pre-create files/dirs that are
+ *                                     meant to be created during the test.
+ *     10-Mar-91       0.0.3 Wittle    Longer RPC timeout while populating
+ *                                     testdir; strstr() bug fix;
+ *                                     '-i' and '-e' options
+ *     06-Mar-91       0.0.2 Wittle    Loop forever pre-filling files.
+ *     22-Feb-91       0.0.1 Wittle    Use signal(2) instead of sigset(2).
+ *     18-Feb-91       0.0.0 Wittle    Change algorythm for determining i/o
+ *                                     sizes, preserve i/o file working set
+ *                                     by using separate files; bugs fixes.
+ *
+ *     nhfsstone renamed to laddis
+ *
+ *     31-Oct-90       2.0.4 Wittle    Many bug fixes.
+ *     24-Aug-90       2.0.3 Wittle    Output compatible w/graphing tools.
+ *     24-July-90      2.0.2 Wittle    Handle mounting below symlinks.
+ *     24-June-90      2.0.1 Wittle    Prefill files with data.
+ *     17-May-90       2.0.0 Bean      Rewrote the guts to use NFS
+ *                                     protocol directly.
+ *                                     Cleaned up self-pacing mechanism.
+ *     08-Nov-89       Guillermo Roa   Ported original version to DG/UX.
+ *     07-Jul-89       Legato Systems  Created.
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/signal.h>
+
+#include <sys/file.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+
+extern getmyhostname(char *, int);
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+/* external routines from RPC and system libraries */
+#if defined(SETPGRP_BSD)
+extern int setpgrp(int, int);
+#endif /* SETPGRP_BSD */
+#if defined(SETPGRP_SYSV)
+extern pid_t setpgrp(void);
+#endif /* SETPGRP_SYSV */
+
+/* forward definitions for local routines */
+static void init_logfile(void);
+static void usage(void);
+static int setmix(char *);
+static int setiodist(FILE *);
+static int parseiodist(FILE *, int);
+static void init_iodist(sfs_io_dist_type *);
+static void init_fss(void);
+static void init_filedist(void);
+static int lad_substr(char *, char *);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void check_clock(void);
+
+int    Tot_client_num_io_files = 0;    /* # of files used for i/o per client */
+int    Tot_client_num_non_io_files =   /* # of files used for i/o per client */
+                               DEFAULT_NFILES;
+int    Files_per_dir =                 /* # of pre-created dirs */
+                               DEFAULT_FILES_PER_DIR;
+int    Tot_client_num_symlinks =       /* # of pre-created symlinks/client */
+                               DEFAULT_NSYMLINKS;
+int    Child_num;
+char *  Prime_client = NULL;            /* Prime client hostname */
+int     Client_num = 1;                 /* My client number */
+int     Tcp = 0;                        /* Flag set on command line */
+char    *sfs_Myname;                 /* name program invoked under */
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+uid_t   Real_uid;                       /* real uid */
+uid_t   Cur_uid;                        /* my uid */
+gid_t   Cur_gid;                        /* my gid list */
+
+static char Client_logname[SFS_MAXNAMLEN];
+
+/*
+ * -----------------  SFS Main and Initialization Code  -----------------
+ */
+
+/*
+ * Read the command line arguments, fork off child processes to
+ * generate NFS load, and perform the local (ie, on this client)
+ * book-keeping for the test and the results.
+ */
+int
+main(
+    int                argc,
+    char       *argv[])
+{
+
+    char       *mix_file;              /* name of mix file */
+    char       *iodist_file;           /* name of block i/o dist table file */
+    int                children;               /* number of children */
+    int                child_num;              /* child index */
+    int                total_load;             /* total client load factor */
+    float      child_load;             /* per child load factor */
+    int                pid;                    /* process id */
+    FILE       *pid_fp;
+    FILE       *iodist_fp;             /* block io dist table file */
+    int                i;
+    int                c;
+    int                Saveerrno;
+    int                ret;
+    int                nsigs = 32;             /* reasonable default */
+    extern char *optarg;
+    extern int optind;
+
+    /*
+     * Place pid in pid log file
+     */
+    if ((pid_fp = fopen(SFS_PNT_PID, "a+")) == NULL) {
+       perror(SFS_PNT_PID);
+       exit(1);
+    }
+
+    (void) fprintf(pid_fp, "%d\n", getpid());
+
+    /* Get program name for stderr printing */
+    sfs_Myname = argv[0];
+
+    check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+
+/*
+ * Get the uid and gid information.
+ */
+    Real_uid = getuid();
+    Cur_gid = getgid();
+
+/*
+ * Form a new process group so our syncrhonization signals don't
+ * cause our parent shell to exit.  Clear the umask.
+ * Default is to use the standard setsid
+ */
+#ifdef SETPGRP3
+    ret = setpgrp3(); /* Work around HP-UX bug */
+#else
+#ifdef SETPGRP_SYSV
+    ret = setpgrp();
+#else
+#ifdef SETPGRP_BSD
+    ret = setpgrp(0, getpid());
+#else
+    ret = setsid();
+#endif /* SETPGRP_BSD */
+#endif /* SETPGRP_SYSV */
+#endif /* SETPGRP3 */
+
+    if (ret == -1) {
+       (void) fprintf(stderr, "%s: failed on setsid/setpgrp\n",
+               sfs_Myname);
+       exit(95);
+    }
+
+    (void) umask(0);
+
+/* Set up default parameters */
+    Validate = 0;
+
+    children = DEFAULT_NPROCS;
+    total_load = DEFAULT_LOAD;
+    mix_file = 0;
+    iodist_file = 0;
+    Nfs_timers = Nfs_udp_timers;
+
+    /* Parse command line arguments */
+    while ((c = getopt(argc, argv, "a:A:b:B:cd:D:f:F:il:m:M:N:p:PQR:S:T:t:V:W:w:z")) != EOF)
+       switch (c) {
+
+       case 'a': /* Percent of files to access */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal access value %s\n",
+                                       sfs_Myname, optarg);
+               exit(96);
+           }
+           Access_percent = atoi(optarg);
+           if (Access_percent < 0 || Access_percent > 100) {
+               (void) fprintf(stderr,
+                      "%s: %% access must be between 0 and 100\n",
+                       sfs_Myname);
+               exit(97);
+           }
+           break;
+
+       case 'A': /* Percent of writes that append */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal append value %s\n",
+                               sfs_Myname, optarg);
+               exit(98);
+           }
+           Append_percent = atoi(optarg);
+           if (Append_percent < 0 || Append_percent > 100) {
+               (void) fprintf(stderr,
+                      "%s: %% append must be between 0 and 100\n",
+                       sfs_Myname);
+               exit(99);
+           }
+           break;
+
+       case 'b': /* Set block size distribution table from file */
+           if ((iodist_fp = fopen(optarg, "r")) == NULL) {
+               Saveerrno = errno;
+               (void) fprintf(stderr, "%s: bad block size file",
+                               sfs_Myname);
+               errno = Saveerrno;
+               perror(optarg);
+               exit(100);
+           }
+           if (setiodist(iodist_fp) < 0) {
+               exit(101);
+           }
+           iodist_file = optarg;
+           (void) fclose(iodist_fp);
+           break;
+
+       case 'B': /* Set the per packet maximum block size */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr,
+                               "%s: illegal block size value %s\n",
+                               sfs_Myname, optarg);
+               exit(102);
+           }
+           Kb_per_block = atoi(optarg);
+           if ((Kb_per_block < 1) ||
+               (Kb_per_block > (DEFAULT_MAX_BUFSIZE/1024))) {
+               (void) fprintf(stderr,
+                               "%s: illegal block size value %s\n",
+                               sfs_Myname, optarg);
+               exit(103);
+           }
+           Bytes_per_block = Kb_per_block * 1024;
+           break;
+
+
+       case 'c': /* Set number of calls */
+           (void) fprintf(stderr, "%s: '-c option no longer supported\n",
+                                   sfs_Myname);
+           exit(104);
+           break;
+
+       case 'd': /* Set debugging level */
+           Debug_level = set_debug_level(optarg);
+           break;
+
+       case 'D': /* Set number of directories */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal dirs value %s\n",
+                               sfs_Myname, optarg);
+               exit(105);
+           }
+           Files_per_dir = atoi(optarg);
+           break;
+
+       case 'f': /* Percent change in file set size */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal file set delta value %s\n",
+                               sfs_Myname, optarg);
+               exit(106);
+           }
+           Fss_delta_percent = atoi(optarg);
+           if (Fss_delta_percent < 0 || Fss_delta_percent > 100) {
+               (void) fprintf(stderr,
+                  "%s: %% file set delta must be between 0 and 100\n",
+                   sfs_Myname);
+               exit(107);
+           }
+           break;
+
+       case 'F': /* Set number of io files */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal files value %s\n",
+                               sfs_Myname, optarg);
+               exit(108);
+           }
+           Tot_client_num_io_files = atoi(optarg);
+           break;
+
+       case 'i': /* Set interactive mode */
+           if (Prime_client != NULL) {
+               (void) fprintf(stderr,
+                           "%s: -i and -M options are incompatible\n",
+                           sfs_Myname);
+               exit(109);
+           }
+           Interactive++;
+           break;
+
+       case 'l': /* Set load */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal load value %s\n",
+                               sfs_Myname, optarg);
+               exit(110);
+           }
+           total_load = atoi(optarg);
+           if (total_load < 0) {
+               (void) fprintf(stderr, "%s: load must be > 0\n",
+                               sfs_Myname);
+               exit(111);
+           }
+           break;
+
+       case 'm': /* Set mix from a file */
+           mix_file = optarg;
+           if (setmix(mix_file) < 0) {
+               exit(112);
+           }
+           break;
+
+       case 'M': /* Set prime_client host name for multi-client sync */
+           if (Interactive) {
+               (void) fprintf(stderr,
+                           "%s: -M and -i options are incompatible\n",
+                           sfs_Myname);
+               exit(113);
+           }
+           Prime_client = optarg;
+           break;
+
+       case 'N': /* Set client number in multi-client run */
+           Client_num = atoi(optarg);
+           if (Client_num <= 0) {
+               (void) fprintf(stderr,
+                               "%s: client number must be > 0\n",
+                               sfs_Myname);
+               exit(114);
+           }
+           break;
+
+       case 'p': /* Set number of child processes */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal procs value %s\n",
+                               sfs_Myname, optarg);
+               exit(115);
+           }
+           children = atoi(optarg);
+           if (children < 0) {
+               (void) fprintf(stderr, "%s: number of children must be > 0\n",
+                               sfs_Myname);
+               exit(116);
+           }
+           break;
+
+       case 'P': /* Populate only */
+           Populate_only++;
+           break;
+
+       case 'Q': /* Set NFS/TCP behaviour */
+           Tcp = 1;
+           Nfs_timers = Nfs_tcp_timers;
+           break;
+
+       case 'R': /* set maximum async read concurrency level */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal read count value %s\n",
+                               sfs_Myname, optarg);
+               exit(117);
+           }
+           Biod_max_outstanding_reads = atoi(optarg);
+           if (Biod_max_outstanding_reads < 0 ||
+                       Biod_max_outstanding_reads > MAX_BIODS) {
+               (void) fprintf(stderr,
+                               "%s: read count must be >= 0 and <= %d\n",
+                               sfs_Myname, MAX_BIODS);
+               exit(118);
+           }
+           break;
+
+       case 'S': /* Set number of symlinks */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr,
+                               "%s: illegal symlinks value %s\n",
+                               sfs_Myname, optarg);
+               exit(119);
+           }
+           Tot_client_num_symlinks = atoi(optarg);
+           break;
+
+       case 'T': /* Set test mode, number following is opnum */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal test value %s\n",
+                               sfs_Myname, optarg);
+               exit(120);
+           }
+           Testop = atoi(optarg);
+           if (Testop >= NOPS) {
+               (void) fprintf(stderr, "%s: illegal test value %d\n",
+                               sfs_Myname, Testop);
+               exit(121);
+           }
+           break;
+
+       case 't': /* Set run time */
+           if (Ops[TOTAL].target_calls > 0) {
+               (void) fprintf(stderr,
+                           "%s: -t and -c options are incompatible\n",
+                           sfs_Myname);
+               exit(122);
+           }
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal time value %s\n",
+                               sfs_Myname, optarg);
+               exit(123);
+           }
+           Runtime = atoi(optarg);
+           if (Runtime < 0) {
+               (void) fprintf(stderr, "%s: run time must be >= 0\n",
+                               sfs_Myname);
+               exit(124);
+           }
+           break;
+
+       case 'V': /* Set Validate Level */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal validate value %s\n",
+                                       sfs_Myname, optarg);
+               exit(125);
+           }
+           Validate = atoi(optarg);
+           if (Validate < 1 || Validate > 3) {
+               (void) fprintf(stderr, "%s: validate must be between 1 and 3\n",
+                                   sfs_Myname);
+               exit(126);
+           }
+           break;
+
+       case 'W': /* set maximum async write concurrency level */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal write count value %s\n",
+                                       sfs_Myname, optarg);
+               exit(127);
+           }
+           Biod_max_outstanding_writes = atoi(optarg);
+           if (Biod_max_outstanding_writes < 0 ||
+                       Biod_max_outstanding_writes > MAX_BIODS) {
+               (void) fprintf(stderr,
+                               "%s: write count must be >= 0 and <= %d\n",
+                               sfs_Myname, MAX_BIODS);
+               exit(128);
+           }
+           break;
+
+       case 'w': /* Set warmup time */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal warmup value %s\n",
+                               sfs_Myname, optarg);
+               exit(129);
+           }
+           Warmuptime = atoi(optarg);
+           if (Warmuptime < 0) {
+               (void) fprintf(stderr, "%s: warmup time must be >= 0\n",
+                               sfs_Myname);
+               exit(130);
+           }
+           break;
+
+       case 'z': /* Do raw data dumps */
+           Dump_data++;
+           break;
+
+       case '?':
+       default:
+           usage();
+           exit(131);
+
+       } /* end switch on arg */
+
+
+   /* compute ops/request for i/o operations */
+   init_iodist(Io_dist_ptr);
+
+   /* compute bytes/file and number of files */
+   init_filedist();
+
+    /* validate all the NFS operations that sfs will use */
+    if (Validate > 0) {
+       /*
+        * -F <number of files > or else
+        * DEFAULT_NFILES
+        */
+       if (Tot_client_num_io_files == 0) {
+               Tot_client_num_io_files = DEFAULT_NFILES;
+       }
+       Num_io_files = Tot_client_num_io_files/children + 1;
+       /* number of non-io files, dir and symlinks base on constants */
+       Num_non_io_files = Tot_client_num_non_io_files/children + 1;
+       Num_dirs = Num_io_files/Files_per_dir + 1;
+       Num_symlinks = Tot_client_num_symlinks/children + 1;
+
+       /* io operations access a subset of the files */
+       Num_working_io_files = ((Num_io_files * Access_percent) / 100) + 1;
+       /* non-io and other operations access all of the files */
+       Num_working_non_io_files = Num_io_files;
+       Num_working_dirs = Num_dirs;
+       Num_working_symlinks = Num_symlinks;
+
+       Validate_ops(argc - optind, &argv[optind]);
+       exit(133);
+    }
+
+    /*
+     * Initial check on the mount arguments, must be at least an
+     * even multiple of the number of procs.
+     */
+    if ((argc - optind) % children) {
+        (void) fprintf(stderr,
+"%s: Invalid mount point list: Not a multiple of number of procs\n",
+                        sfs_Myname);
+        exit(182);
+    }
+
+    /*
+     * -F <number of io files > or else
+     * base files set on load ; this in NON-SPEC though
+     */
+    if (Tot_client_num_io_files == 0) {
+       Tot_client_num_io_files = ((DEFAULT_BYTES_PER_OP / 1024  * total_load)
+                            / (1024)) * files_per_megabyte;
+    }
+    Num_io_files = Tot_client_num_io_files/children + 1;
+
+    /*   
+     * Number of non-io files scales with load and is set at 2% of all files,
+     * but at least DEFAULT_NFILES worth.
+     */  
+    Tot_client_num_non_io_files = Tot_client_num_io_files * 0.02;
+    if (Tot_client_num_non_io_files < DEFAULT_NFILES)
+        Tot_client_num_non_io_files = DEFAULT_NFILES;
+    Num_non_io_files = Tot_client_num_non_io_files/children + 1;
+    /* number of dir and symlinks base on constants */
+    Num_dirs = Num_io_files/Files_per_dir + 1;
+    Num_symlinks = Tot_client_num_symlinks/children + 1;
+
+    /* io operations access a subset of the files */
+    Num_working_io_files = ((Num_io_files * Access_percent) / 100) + 1;
+
+    /* non-io and other operations access all of the files */
+    Num_working_non_io_files = Num_io_files;
+    Num_working_dirs = Num_dirs;
+    Num_working_symlinks = Num_symlinks;
+
+    /*
+     * If we are doing a timed test, we still need an
+     * estimate of how many calls are needed in order to
+     * judge our progress.
+     * If we are doing a test for a number of calls, we still need an
+     * estimate of how long the test will take in order to
+     * establish the time interval between progress checks.
+     */
+    if (Timed_run) {
+       /*
+        * the total number of calls will be divided between the children
+        * when they are forked off.
+        */
+       Ops[TOTAL].target_calls = Runtime * total_load;
+    } else {
+       Runtime = (int) ((float) Ops[TOTAL].target_calls / (float) total_load);
+    }
+
+    /*
+     * multi-client sync support
+     * offset the Runtime value by MULTICLIENT_OFFSET seconds.
+     * This offset prevents the client from finishing before
+     * the Prime Client tells it to 'STOP'. The MULTICLIENT_OFFSET is larger
+     * than the time_out value on the Prime-Client; so in case the client
+     * does not stop when it's told to, the Prime-client should time_out.
+     */
+    if (Prime_client && Timed_run)
+       Runtime += MULTICLIENT_OFFSET;
+
+    /* compute file set sizes */
+    init_fss();
+
+    /* Set up synchronization and results log file */
+    init_logfile();
+
+    /*
+     * setup value of nsigs
+     */
+#ifdef __NSIG
+    nsigs = __NSIG;
+#endif
+#ifdef _NSIG
+    nsigs = _NSIG;
+#endif
+#ifdef NSIG
+    nsigs = NSIG;
+#endif
+#if defined(SOLARIS2) && !defined(_sys_nsig)
+    nsigs = _sys_siglistn;
+#endif
+
+    /* Set up the signal handlers for all signals */
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    {
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       if (DEBUG_PARENT_GENERAL) {
+           if (nsigs == 0) {
+               (void) fprintf (stderr,
+                   "WARNING: nsigs not defined, no extra signals caught\n");
+           }
+           for (i = 1; i < nsigs; i++) {
+/* attempt to set up signal handler for these signals give an error !! K.T. */
+               if (i!=SIGCHLD && i!=SIGKILL && i!=SIGSTOP && i!=SIGCONT) {
+                   if (sigaction(i,&sig_act,&old_sig_act) == -1) {
+                       if (errno == EINVAL) {
+                           (void) fprintf (stderr,
+                                       "Skipping invalid signal %d\n", i);
+                       } else {
+                           perror("sigaction failed");
+                           exit(134);
+                       }
+                   }
+               }
+           }
+        }
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_alarm;
+       if (sigaction(SIGALRM,&sig_act,&old_sig_act) != 0) {
+           perror("sigaction failed: SIGALRM");
+           exit(136);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+
+       sig_act.sa_handler = sfs_startup;
+       if (sigaction(SIGUSR1,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGUSR1");
+           exit(138);
+       }
+
+       sig_act.sa_handler = sfs_stop;
+       if (sigaction(SIGUSR2,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGUSR2");
+           exit(139);
+       }
+    }
+#else
+    if (DEBUG_PARENT_GENERAL) {
+       if (nsigs == 0) {
+           (void) fprintf (stderr,
+                   "WARNING: nsigs not defined, no extra signals caught\n");
+       }
+       for (i = 1; i < nsigs; i++) {
+           if (i!=SIGCHLD)
+               (void) signal(i, generic_catcher);
+       }
+    }
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    (void) signal(SIGALRM, sfs_alarm);
+    (void) signal(SIGTERM, sfs_cleanup);
+    (void) signal(SIGUSR1, sfs_startup);
+    (void) signal(SIGUSR2, sfs_stop);
+#endif
+
+    /* Fork children */
+    for (child_num = 0; child_num < children; child_num++) {
+       pid = fork();
+       if (pid == -1) {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "%s: can't fork children.", sfs_Myname);
+           errno = Saveerrno;
+           perror("fork");
+           (void) generic_kill(0, SIGINT);
+           exit(140);
+       } else if (pid == 0) {
+           break;      /* get out of child creation */
+       }
+       (void) fprintf(pid_fp, "%d\n", pid);
+    } /* end for forking kids */
+    (void) fclose(pid_fp);
+
+    /*
+     * Parent: wait for kids to get ready, start them, wait for them to
+     * finish, read and accumulate results.
+     */
+    if (pid != 0) {
+       if (setuid(Real_uid) != 0) {
+          (void) fprintf(stderr,"%s: %s%s\n",
+                  sfs_Myname, "cannot perform setuid operation.\n",
+                  "Do `make install` as root.\n");
+       }
+
+       /* I'm the parent - let the common code signal handlers know it */
+       Child_num = -1;
+
+       parent(children, total_load, mix_file, iodist_file);
+
+       /* Clean up and exit. */
+       (void) close(Log_fd);
+       (void) unlink(Logname);
+       exit(0);
+
+    } /* parent */
+
+    /*
+     * Children : initialize, then notify parent through log file,
+     * wait to get signal, beat the snot out of the server, write
+     * stats to the log file, and exit.
+     */
+    if (pid == 0) {
+
+       /* I'm a child - let the common code signal handlers know it */
+       Child_num = child_num;
+
+       /*
+        * Determine my share of the calls and load (including any left over)
+        * The call target for each child differs by at most 1 call.
+        * The load rate for each child differs by at most 1 call/sec.
+        */
+       Ops[TOTAL].target_calls = Ops[TOTAL].target_calls / children;
+       if (child_num <= Ops[TOTAL].target_calls % children) {
+           Ops[TOTAL].target_calls++;
+       }
+       child_load = (float) total_load / (float) children;
+
+       /*
+        * Sleep a bit so the parent can catch up after procreating all us
+        * children.
+        */
+       (void) sleep(10);
+
+       child(child_num, children, child_load, argc - optind, &argv[optind]);
+       exit(0);
+
+    } /* child */
+
+    (void) unlink(SFS_PNT_PID);
+
+    return(0);
+
+} /* main */
+
+
+/*
+ * -----------------  Initalization of Parent/Child  ---------------------
+ */
+
+/*
+ * Open the multi-client synchronization file with append mode.
+ */
+static void
+init_logfile(void)
+{
+    FILE       *cl_log_fd;
+    int                Saveerrno;
+
+    (void) sprintf(Logname, "%s%d", CHILD_SYNC_LOG, Client_num);
+    Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
+    if (Log_fd == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't open log file %s ", sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror(Logname);
+       exit(141);
+    }
+    if (chown(Logname, Real_uid, Cur_gid) ==-1) {
+       perror("chown");
+       (void) fprintf(stderr, "%s: chown failed\n", sfs_Myname);
+    }
+
+    /* if multi-client execution then init client sync log */
+    if (Prime_client != NULL) {
+       /* init logfile and write process id */
+       (void) sprintf(Client_logname, "%s%d",
+                       SFS_CLIENT_SYNC_LOG, Client_num);
+       cl_log_fd = fopen(Client_logname, "w+");
+       if (chown(Client_logname, Real_uid, Cur_gid) ==-1) {
+               perror("chown");
+               (void) fprintf(stderr, "%s: chown failed\n", sfs_Myname);
+       }
+       if (cl_log_fd == NULL) {
+           Saveerrno = errno;
+           (void) fprintf(stderr,
+               "%s: can't open Client synchronization file %s ",
+                           sfs_Myname, Client_logname);
+           errno = Saveerrno;
+           perror(Client_logname);
+           exit(142);
+       } else {
+           /* store parent pid */
+           (void) fprintf(cl_log_fd, "%d", (int)getpid());
+           (void) fclose(cl_log_fd);
+       }
+    } /* init multi-client sync log */
+
+} /* init_logfile */
+
+/*
+ * ------------------------  Utility Routines  --------------------------
+ */
+
+
+/*
+ * Print the program's usage message.
+ * Usage: sfs [-l load] [-p procs] [-w warmup] [-t time]
+ *               [-m mix_file] [-B block_size] [-b blocksz_file]
+ *              [-f file_set_delta] [-a access_pnct]
+ *              [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]
+ *              [-d debug_level] [-i] [-P] [-T op_num]
+ *              [-V validation_level] [-z] [-Q]
+ *              [-R biod_reads] [-W biod_writes]
+ *              [-M prime_client_hostname] [-N client_cnt]
+ */
+static void
+usage(void)
+{
+    (void) fprintf(stderr,
+      "Usage: %s [-l load] [-p procs] [-w warmup] [-t time]\n", sfs_Myname);
+    (void) fprintf(stderr,
+      "              [-m mix_file] [-B block_size] [-b blocksz_file]\n");
+    (void) fprintf(stderr,
+      "              [-f file_set_delta] [-a access_pnct]\n");
+    (void) fprintf(stderr,
+      "              [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]\n");
+    (void) fprintf(stderr,
+      "              [-d debug_level] [-i] [-P] [-T op_num]\n");
+    (void) fprintf(stderr,
+      "              [-V validation_level] [-z] [-Q]\n");
+    (void) fprintf(stderr,
+      "              [-R biod_reads] [-W biod_writes]\n");
+    (void) fprintf(stderr,
+      "              [-M prime_client_hostname] [-N client_cnt]\n");
+} /* usage */
+
+
+
+/*
+ * --------------  Command Line File Parsing  -------------------
+ */
+
+/*
+ * Constants for mix file
+ */
+#define LINELEN         128             /* max bytes/line in mix file */
+#define MIX_START       0
+#define MIX_DATALINE    1
+#define MIX_DONE        2
+#define MIX_FIRSTLINE   3
+
+/*
+ * Parse the operation mix file 'mix_file'.
+ *
+ * ORIGINAL PRE-SFS1.2 format:
+ *     Assumes that the input file is in the same format as
+ *     the output of the nfsstat(8) command.
+ *
+ *     Uses a simple state transition to keep track of what to expect.
+ *     Parsing is done a line at a time.
+ *
+ *     State           Input                   action          New state
+ *     MIX_START       ".*nfs:.*"              skip one line   MIX_FIRSTLINE
+ *     MIX_FIRSTLINE   ".*[0-9]*.*"            get calls       MIX_DATALINE
+ *     MIX_DATALINE    "[0-9]* [0-9]*%"X6      get op counts   MIX_DATALINE
+ *     MIX_DATALINE    "[0-9]* [0-9]*%"X4      get op counts   MIX_DONE
+ *     MIX_DONE        EOF                     return
+ *
+ *     We read operation counts from the mix file
+ *     and compute our own mix percentages,
+ *     rather than using those in the mix file.
+ *
+ * NEW SFS1.2 format version #2:
+ *     SFS MIXFILE VERSION 2           Version header (must come first line)
+ *     "^#.*"                          Comment (any line except first)
+ *     "%s [0-9]*%"                    Op name Op percentage
+ */
+static int
+setmix(
+    char *     mix_file)
+{
+    int                state;          /* current state of state machine */
+    int                got;            /* number of items read from input line */
+    int                opnum;          /* operation number index */
+    int                calls;          /* total number of calls in mix */
+    char       line[LINELEN];  /* input line buffer */
+    char       op_name[LINELEN];       /* name buffer */
+    int                mix_pcnt;
+    unsigned int       len;    /* length of input line */
+    FILE       *mix_fp;        /* mix file */
+    int                vers;           /* mix file version number */
+    sfs_op_type *op_ptr;
+
+    if ((mix_fp = fopen(mix_file, "r")) == NULL) {
+       (void) fprintf(stderr, "%s: bad mix file", sfs_Myname);
+       perror(mix_file);
+       return(-1);
+    }
+
+    if (fgets(line, LINELEN, mix_fp) == NULL) {
+       (void) fprintf(stderr, "%s: bad mix format - unexpected empty file\n",
+                                       sfs_Myname);
+       (void) fclose(mix_fp);
+       return (-1);
+    }
+
+    opnum = 0;
+
+    /*
+     * Look for initial version string
+     */
+    got = sscanf(line, "SFS MIXFILE VERSION %d", &vers);
+    if (got != 1) {
+       /*
+        * Check to see if this is old mixfile
+        */
+       len = strlen(line);
+       if (len < 4 || lad_substr(line, "nfs:") == 0) {
+           (void) fprintf(stderr, "%s: bad mix format - initial line '%s'\n",
+                                       sfs_Myname, line);
+           (void) fclose(mix_fp);
+           return (-1);
+       }
+       vers = 1;
+    }
+
+    if (vers == 1) {
+       /*
+        * Old style mix file
+        */
+       state = MIX_START;
+       while (state != MIX_DONE && fgets(line, LINELEN, mix_fp)) {
+
+           switch (state) {
+               case MIX_START:
+                   /*
+                    * Ate first line after nfs:
+                    */
+                   state = MIX_FIRSTLINE;
+                   break;
+
+               case MIX_FIRSTLINE:
+                   got = sscanf(line, "%d", &calls);
+                   if (got != 1) {
+                       (void) fprintf(stderr,
+                       "%s: bad mix format - can't find 'calls' value %d\n",
+                                   sfs_Myname,got);
+                               (void) fclose(mix_fp);
+                               return (-1);
+                   }
+                   if (fgets(line, LINELEN, mix_fp) == NULL) {
+                       (void) fprintf(stderr,
+                       "%s: bad mix format - unexpected EOF after 'calls'\n",
+                                   sfs_Myname);
+                       (void) fclose(mix_fp);
+                       return (-1);
+                   }
+                   state = MIX_DATALINE;
+                   break;
+
+               case MIX_DATALINE:
+                   got = sscanf(line,
+              "%d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%%",
+                           &Ops[opnum].mix_pcnt,
+                           &Ops[opnum + 1].mix_pcnt,
+                           &Ops[opnum + 2].mix_pcnt,
+                           &Ops[opnum + 3].mix_pcnt,
+                           &Ops[opnum + 4].mix_pcnt,
+                           &Ops[opnum + 5].mix_pcnt,
+                           &Ops[opnum + 6].mix_pcnt);
+
+                   if (got == 4 && opnum == 14) {
+                       /* looks like the last line */
+                       state = MIX_DONE;
+                   } else if (got == 7) {
+                       opnum += 7;
+                       if (fgets(line, LINELEN, mix_fp) == NULL) {
+                           (void) fprintf(stderr,
+                       "%s: bad mix format - unexpected EOF after 'calls'\n",
+                                       sfs_Myname);
+                           (void) fclose(mix_fp);
+                           return (-1);
+                       }
+                   } else {
+                       (void) fprintf(stderr,
+                           "%s: bad mix format - can't find %d op values\n",
+                               sfs_Myname, got);
+                       (void) fclose(mix_fp);
+                       return (-1);
+                   }
+                   break;
+
+               default:
+                   (void) fprintf(stderr,
+                               "%s: error parsing mix file - bad state %d\n",
+                               sfs_Myname, state);
+                   (void) fclose(mix_fp);
+                   return (-1);
+           } /* end switch on state */
+        } /* end while there are lines to read */
+
+        if (state != MIX_DONE) {
+           (void) fprintf(stderr, "%s: bad mix format - unexpected EOF\n",
+               sfs_Myname);
+           (void) fclose(mix_fp);
+           return (-1);
+        }
+        for (opnum = 0; opnum < NOPS; opnum++) {
+           Ops[opnum].mix_pcnt = Ops[opnum].mix_pcnt * 100 / calls
+                            + ((Ops[opnum].mix_pcnt * 1000 / calls % 10) >= 5);
+        }
+        (void) fclose(mix_fp);
+        return (0);
+    }
+    if (vers == 2) {
+       /*
+        * New style mix file
+        */
+       while (fgets(line, LINELEN, mix_fp) != NULL) {
+           if (line[0] == '#')                 /* Comment line */
+               continue;
+           got = sscanf(line, "%s %d", op_name, &mix_pcnt);
+           if (got != 2) {
+               (void) fprintf(stderr,
+                           "%s: bad mix format - can't find op values: %s\n",
+                               sfs_Myname, line);
+               (void) fclose(mix_fp);
+               return (-1);
+           }
+           op_ptr = Ops;
+           while (strcmp(op_ptr->name, "TOTAL") != 0) {
+               if (strcmp(op_ptr->name, op_name) == 0) {
+                   op_ptr->mix_pcnt = mix_pcnt;
+                   break;
+               }
+               op_ptr++;
+           }
+           if (strcmp(op_ptr->name, "TOTAL") == 0) {
+               (void) fprintf(stderr,
+                           "%s: unknown op name: %s\n",
+                               sfs_Myname, op_name);
+               (void) fclose(mix_fp);
+               return (-1);
+           }
+        }
+       /*
+        * Make sure that the total mix percentages == 100
+        */
+        op_ptr = Ops;
+       mix_pcnt = 0;
+        while (strcmp(op_ptr->name, "TOTAL") != 0) {
+           mix_pcnt += op_ptr->mix_pcnt;
+           op_ptr++;
+        }
+       if (mix_pcnt != 100) {
+           (void) fprintf(stderr,
+                           "%s: WARNING total mix percentage %d != 100\n",
+                               sfs_Myname, mix_pcnt);
+       }
+        (void) fclose(mix_fp);
+       return (0);
+    }
+
+    (void) fprintf(stderr, "%s: Unknown mix file version number %d\n",
+                               sfs_Myname, vers);
+    (void) fclose(mix_fp);
+    return (-1);
+} /* setmix */
+
+
+/*
+ * Parse the block I/O distribution file 'fp'.
+ */
+static int
+setiodist(
+    FILE *     fp)
+{
+    int                i;
+
+    /* first, read and parse the i/o distribution file for syntax and size */
+    if (parseiodist(fp, 1) == -1) {
+       exit(143);
+    }
+    (void) fseek(fp, 0, SEEK_SET);
+
+    /* read the i/o distribution file into the i/o dist table */
+    if (parseiodist(fp, 2) == -1) {
+       exit(144);
+    }
+
+    if (DEBUG_PARENT_GENERAL) {
+       (void) fprintf(stdout, "I/o Distribution Table\n");
+       (void) fprintf(stdout, "Read:\n");
+       (void) fprintf(stdout, "\tpcnt bufs frags\n");
+       for (i = 0 ; ; i++) {
+           (void) fprintf(stdout, "\t%4d %4d %5d\n", Io_dist_ptr->read[i].pcnt,
+                       Io_dist_ptr->read[i].bufs, Io_dist_ptr->read[i].frags);
+           if (Io_dist_ptr->read[i].pcnt == 100)
+               break;
+       }
+
+       (void) fprintf(stdout, "Write:\n");
+       (void) fprintf(stdout, "\tpcnt bufs frags\n");
+       for (i = 0; ; i++) {
+           (void) fprintf(stdout, "\t%4d %4d %5d\n",
+                           Io_dist_ptr->write[i].pcnt,
+                           Io_dist_ptr->write[i].bufs,
+                           Io_dist_ptr->write[i].frags);
+           if (Io_dist_ptr->write[i].pcnt == 100)
+               break;
+       }
+       (void) fprintf(stdout, "Maximum file size: %d KB (%d * %d KB)\n",
+                       Io_dist_ptr->max_bufs * Kb_per_block,
+                       Io_dist_ptr->max_bufs, Kb_per_block);
+    }
+    return(0);
+} /* setiodist */
+
+
+/*
+ * Block/File Distribution file parser.
+ * Assumes that the input file is in the following format:
+ *
+ *
+ *     READ_KEY_WORD
+ *     percent         block_cnt               fragment_flag
+ *        .                 .                        .
+ *        .                 .                        .
+ *        .                 .                        .
+ *     WRITE_KEY_WORD
+ *     percent         block_cnt               fragment_flag
+ *        .                 .                        .
+ *        .                 .                        .
+ *        .                 .                        .
+ *
+ *
+ * Notes:
+ *     - The READ_KEY_WORD is "Read", the WRITE_KEY_WORD is "Write".
+ *     - For each key word, the percent fields must sum to 100.
+ *     - Fragment is either true (1) or false (0)
+ *     - Maximum file size (and transfer size) is the largest
+ *       eight_k_cnt * 8KB plus 7 Kb for fragments
+ *
+ *
+ * Uses a simple state transition to keep track of what to expect.
+ * Parsing is done a line at a time.
+ *
+ * State       Input                   action          New state
+ * -----       --------------------    -------------   ---------
+ * START       "Read"                  skip one line   READ
+ * START       "Write"                 skip one line   WRITE
+ * READ                "[0-9]* [0-9]* [01]"    get values      READ
+ * READ                "Write"                 skip one line   WRITE
+ * WRITE       "[0-9]* [0-9]* [01]"    get values      WRITE
+ * WRITE       "Read"                  skip one line   READ
+ * DONE                EOF                     return
+ *
+ * Pass 1 reads the file and allocates table space.
+ * Pass 2 reads the file data into the tables.
+ */
+static int
+parseiodist(
+    FILE *     fp,
+    int                pass)
+{
+    int                state;          /* current state of state machine */
+    int                got;            /* number of items read from input line */
+    int                pcnt;           /* percent read from input line */
+    int                bufs;           /* eight_kb_buffer_cnt read from input line */
+    int                frags;          /* fragment flag read from input line */
+    int                rbucket;        /* current read distribution table bucket */
+    int                wbucket;        /* current write distribution table bucket */
+    int                rpcnt;          /* cumulative percent for read buckets */
+    int                wpcnt;          /* cumulative percent for write buckets */
+    char       key[5];         /* keyword buffer */
+    char       line[LINELEN];  /* input line buffer */
+    int                nextline;
+
+    /*
+     * Pass 1 reads, sizes, and error checks the input
+     * and then allocates space for the distribution tables.
+     * Pass 2 reads the input into the allocated tables.
+     */
+
+    rbucket = 0;
+    wbucket = 0;
+    rpcnt = 0;
+    wpcnt = 0;
+    state = IO_DIST_START;
+
+    while (fgets(line, LINELEN, fp)) {
+
+       nextline = 0;
+       while (nextline == 0) {
+
+           if (state == IO_DIST_READ) {
+               got = sscanf(line, "%d %d %d", &pcnt, &bufs, &frags);
+               if (got != 3) {
+                   state = IO_DIST_START;
+                   continue; /* same line, but goto new state */
+               }
+               if (pass == 1) {
+                   rbucket++;
+                   rpcnt += pcnt;
+                   if (frags != 0 && frags != 1) {
+                       (void) fprintf(stderr,
+                           "%s: bad i/o dist format - bad fragment value\n",
+                                       sfs_Myname);
+                       return(-1);
+                   }
+               } else {
+                   rpcnt += pcnt;
+                   Io_dist_ptr->read[rbucket].pcnt = rpcnt;
+                   Io_dist_ptr->read[rbucket].bufs = bufs;
+                   Io_dist_ptr->read[rbucket].frags = frags;
+                   rbucket++;
+               }
+               if (DEBUG_CHILD_FILES) {
+                   (void) fprintf(stdout, "p=%d b=%d f=%d rpcnt=%d\n",
+                                   pcnt, bufs, frags, rpcnt);
+                   (void) fflush(stdout);
+               }
+
+               /* read next line in file */
+               nextline++;
+               break;
+           }
+
+           if (state == IO_DIST_WRITE) {
+               got = sscanf(line, "%d %d %d", &pcnt, &bufs, &frags);
+               if (got != 3) {
+                   state = IO_DIST_START;
+                   continue; /* same line, but goto new state */
+               }
+               if (pass == 1) {
+                   wbucket++;
+                   wpcnt += pcnt;
+                   if (frags != 0 && frags != 1) {
+                       (void) fprintf(stderr,
+                           "%s: bad i/o dist format - bad fragment value\n",
+                                       sfs_Myname);
+                       return(-1);
+                   }
+               } else {
+                   wpcnt += pcnt;
+                   Io_dist_ptr->write[wbucket].pcnt = wpcnt;
+                   Io_dist_ptr->write[wbucket].bufs = bufs;
+                   Io_dist_ptr->write[wbucket].frags = frags;
+                   wbucket++;
+               }
+               if (DEBUG_CHILD_FILES) {
+                   (void) fprintf(stdout, "p=%d b=%d f=%d wpcnt=%d\n",
+                                   pcnt, bufs, frags, wpcnt);
+                   (void) fflush(stdout);
+               }
+               /* read next line in file */
+               nextline++;
+               break;
+           }
+
+           if (state == IO_DIST_START) {
+               got = sscanf(line, "%s", key);
+               if (got != 1 || (strlen(key) != 5)){
+                   (void) fprintf(stderr,
+                           "%s: bad i/o dist format - invalid keyword %s\n",
+                                   sfs_Myname, key);
+                   return(-1);
+               }
+               if (!strcmp(key, "Read") || !strcmp(key, "read")) {
+                   if (rbucket != 0) {
+                       (void) fprintf(stderr,
+                       "%s: bad i/o dist format - too many read keywords\n",
+                                       sfs_Myname);
+                       return(-1);
+                   }
+                   rpcnt = 0;
+                   state = IO_DIST_READ;
+
+                   /* read next line in file */
+                   nextline++;
+                   break;
+               }
+               if (!strcmp(key, "Write") || !strcmp(key, "write")) {
+                   if (wbucket != 0) {
+                       (void) fprintf(stderr,
+                      "%s: bad i/o dist format - too many write keywords\n",
+                                       sfs_Myname);
+                       return(-1);
+                   }
+                   wpcnt = 0;
+                   state = IO_DIST_WRITE;
+
+                   /* read next line in file */
+                   nextline++;
+                   break;
+               }
+               (void) fprintf(stderr,
+                           "%s: bad i/o dist format - unknown keyword %s\n",
+                               sfs_Myname, key);
+               return(-1);
+           }
+
+       } /* end while processing this line */
+    } /* end while more lines */
+
+    if (pass == 1) {
+
+       /* error check the input */
+       if (rbucket == 0) {
+           (void) fprintf(stderr,
+                   "%s: bad i/o dist format - no read distribution data\n",
+                           sfs_Myname);
+           return(-1);
+       }
+       if (rpcnt != 100) {
+           (void) fprintf(stderr,
+                       "%s: bad i/o dist format - read total percent != 100\n",
+                           sfs_Myname);
+           return(-1);
+       }
+       if (wbucket == 0) {
+           (void) fprintf(stderr,
+                   "%s: bad i/o dist format - no write distribution data\n",
+                           sfs_Myname);
+           return(-1);
+       }
+       if (wpcnt != 100) {
+           (void) fprintf(stderr,
+                   "%s: bad i/o dist format - write percent total != 100\n",
+                           sfs_Myname);
+           return(-1);
+       }
+
+       /* allocate space for the table */
+       if ((Io_dist_ptr = (sfs_io_dist_type *)
+               malloc(sizeof(sfs_io_dist_type))) == NULL) {
+           (void) fprintf(stderr,
+                   "%s: block i/o distribution table allocation failed\n",
+                           sfs_Myname);
+               return(-1);
+       }
+       if ((Io_dist_ptr->read = (sfs_io_op_dist_type *)
+               malloc(rbucket*sizeof(sfs_io_op_dist_type))) == NULL) {
+           (void) fprintf(stderr,
+                   "%s: read distribution table allocation failed\n", sfs_Myname);
+           return(-1);
+       }
+       if ((Io_dist_ptr->write = (sfs_io_op_dist_type *)
+               malloc(wbucket*sizeof(sfs_io_op_dist_type)))==NULL) {
+           (void) fprintf(stderr,
+                   "%s: write distribution table allocation failed\n", sfs_Myname);
+           return(-1);
+       }
+
+    }
+    return(0);
+
+} /* parseiodist */
+
+
+/*
+ * Compute the max i/o transfer size and average ops per request
+ * for the block transfer distribution table.
+ */
+static void
+init_iodist(
+    sfs_io_dist_type   *       io_dist_ptr)
+{
+    int                                max_bufs;
+    double                     weighted_ops;
+    double                     previous_pcnt;
+    int                                i;
+
+    /*
+     * compute expected number of ops for multi-op requests.
+     * the calculation assumes that if a i/o distribution table
+     * entry specifies that a fragment is to be generated, then
+     * exactly one OTW operation will result.
+     */
+    max_bufs = 0;
+
+    weighted_ops = 0.0;
+    previous_pcnt = 0.0;
+    for (i = 0; ; i++) {
+       weighted_ops += (io_dist_ptr->read[i].pcnt - previous_pcnt) *
+                     (io_dist_ptr->read[i].bufs + io_dist_ptr->read[i].frags);
+       previous_pcnt = io_dist_ptr->read[i].pcnt;
+       if (io_dist_ptr->read[i].bufs > max_bufs)
+           max_bufs = io_dist_ptr->read[i].bufs;
+       if (io_dist_ptr->read[i].pcnt == 100)
+           break;
+    }
+    io_dist_ptr->avg_ops_per_read_req = weighted_ops / 100.0;
+
+    weighted_ops = 0.0;
+    previous_pcnt = 0.0;
+    for (i = 0; ; i++) {
+       weighted_ops += (io_dist_ptr->write[i].pcnt - previous_pcnt) *
+                   (io_dist_ptr->write[i].bufs + io_dist_ptr->write[i].frags);
+       previous_pcnt = io_dist_ptr->write[i].pcnt;
+       if (io_dist_ptr->write[i].bufs > max_bufs)
+           max_bufs = io_dist_ptr->write[i].bufs;
+       if (io_dist_ptr->write[i].pcnt == 100)
+           break;
+    }
+    io_dist_ptr->avg_ops_per_write_req = weighted_ops / 100.0;
+
+    io_dist_ptr->max_bufs = max_bufs + 1;
+
+} /* init_iodist */
+
+static void
+init_filedist()
+{
+    int i;
+    int cur_pcnt;
+    int num_files = 0;
+    int prev_pcnt = 0;
+    int tot_size = 0;
+
+    /*
+     * Calculate the average number of bytes per file
+     */
+    for (i = 0; Default_file_size_dist[i].size != 0; i++) {
+        cur_pcnt = Default_file_size_dist[i].pcnt - prev_pcnt;
+        num_files += cur_pcnt;
+       tot_size += (Default_file_size_dist[i].size * 1024) * cur_pcnt;
+       prev_pcnt = Default_file_size_dist[i].pcnt;
+    }
+
+    avg_bytes_per_file = tot_size / num_files;
+    files_per_megabyte = (((1024*1024) + avg_bytes_per_file) \
+                                        / avg_bytes_per_file);
+}
+
+static void
+init_fss()
+{
+    int Delta_fss_bytes;
+
+    Base_fss_bytes = Num_working_io_files * (avg_bytes_per_file / 1024);
+    Total_fss_bytes = Num_io_files * (avg_bytes_per_file / 1024);
+    Cur_fss_bytes = Base_fss_bytes;
+    Delta_fss_bytes = (Base_fss_bytes * Fss_delta_percent) / 100;
+    Limit_fss_bytes = Base_fss_bytes + Delta_fss_bytes;
+    Most_fss_bytes = Base_fss_bytes;
+    Least_fss_bytes = Base_fss_bytes;
+}
+
+/*
+ * return true if 'sp' contains the substring 'subsp', false otherwise
+ */
+static int
+lad_substr(
+    char *             sp,
+    char *             subsp)
+{
+    unsigned int       found;
+    int                        want;
+    char *             s2;
+
+    if (sp == NULL || subsp == NULL) {
+       return (0);
+    }
+
+    want = strlen(subsp);
+
+    while (*sp != '\0') {
+       while (*sp != *subsp && *sp != '\0') {
+           sp++;
+       }
+       found = 0;
+       s2 = subsp;
+       while (*sp == *s2 && *sp != '\0') {
+           sp++;
+           s2++;
+           found++;
+       }
+       if (found == want) {
+           return (1);
+       }
+    }
+    return (0);
+
+} /* lad_substr */
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+/* sfs_c_chd.c */
+/* sfs_c_man.c */
+
diff --git a/TBBT/trace_play/sfs_c_mnt.c b/TBBT/trace_play/sfs_c_mnt.c
new file mode 100644 (file)
index 0000000..8f60387
--- /dev/null
@@ -0,0 +1,573 @@
+#ifndef lint
+static char sfs_c_mntSid[] = "@(#)sfs_c_mnt.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_mnt.c ---------------------
+ *
+ *      The sfs child.  Routines to handle mount points.
+ *
+ *.Exported_Routines
+ *     void init_mount_point(int, char *, CLIENT *)
+ *
+ *.Local_Routines
+ *     int pseudo_mount(char *, int, char *, CLIENT *)
+ *
+ *.Revision_History
+ *     2-Jul-92        Teelucksingh    Added code for OSF/1
+ *                                     use of getmntinfo().
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <fcntl.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+struct hostent   *Server_hostent;
+
+/*
+ * -------------------------  Constants  -------------------------
+ */
+
+/*
+ * Number of times a load generating process will retry amount.
+ * Each load generating process also picks a client shifted
+ * mount start time, and executes a backoff on retry time on
+ * failure.
+ */
+#define NUMBER_MOUNT_RETRIES   10
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+/* forward definitions for local routines */
+CLIENT * lad_getmnt_hand(char *);
+static int pseudo_mount(char *, int, char *, CLIENT *);
+
+/*
+ * Mounts are retried when an RPC timeout occurs, in the mainline
+ * code. They are not retried by the RPC clnt_call routine, as the
+ * timeout values are set now.
+ */
+static struct timeval Mount_timer = {  10,  0 };
+
+
+/*
+ * -------------------------  Mount Point Routines  -------------------------
+ */
+
+
+/*
+ * mount the testdir 'dirnum' under the parent directory 'parentdir'.
+ */
+void
+init_mount_point(
+    int                dirnum,
+    char *     parentdir,
+    CLIENT *   mount_client_ptr)
+{
+    char       pnt_dir[SFS_MAXPATHLEN];      /* test dir component name */
+    char       testdirname[SFS_MAXPATHLEN];  /* test dir component name */
+    char       export_fsname[SFS_MAXPATHLEN]; /* "host:path" exported fs */
+    sfs_fh_type file_handle;
+    char       *fh_ptr;
+    char       *cp;
+    int                ret;
+    sfs_fh_data *fh_datap, *Ex_fh_datap;
+
+    fh_datap= calloc(1,sizeof(sfs_fh_data));
+    (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
+    (void) memset((char *)&file_handle, 0, sizeof(file_handle));
+    file_handle.fh_data = fh_datap;
+    file_handle.dir = &Export_dir;
+
+    Ex_fh_datap = (sfs_fh_data *) calloc(1,sizeof(sfs_fh_data));
+    Export_dir.fh_data = Ex_fh_datap;
+
+    (void) strcpy(pnt_dir, parentdir);
+
+    cp = strchr(pnt_dir, ':');
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, parentdir);
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(86);
+    }
+
+    *cp++ = '\0';
+
+    /*
+     * Now we have the parent directory in the form:
+     *         host:host_path
+     *
+     * First we get the file handle for parent directory
+     *
+     * Verify that the server is running the correct version of
+     * the NFS protocol specification and then proceed to get
+     * the exported fh from the server.
+     */
+    (void) strcpy(testdirname, pnt_dir);
+    (void) strcat(testdirname, ":");
+    (void) strcat(testdirname, cp);
+    (void) strcpy(export_fsname, testdirname);
+
+    if (nfs_version == NFS_VERSION) {
+       (void) memset((char *) &Export_dir.fh2, '\0', sizeof (Export_dir.fh2));
+       fh_ptr = (char *)&Export_dir.fh2;
+    } else if (nfs_version == NFS_V3) {
+       (void) memset((char *) &Export_dir.fh3, '\0', sizeof (Export_dir.fh3));
+       fh_ptr = (char *)&Export_dir.fh3;
+    }
+
+    ret = pseudo_mount(export_fsname, nfs_version,
+                                       fh_ptr, mount_client_ptr);
+    if (ret < 0) {
+       if (ret == -2)  {
+           (void) fprintf(stderr,
+               "%s: NFS Protocol Version %lu verification failed.\n",
+               sfs_Myname, (uint32_t)nfs_version);
+       }
+       else  {
+           (void) fprintf(stderr, "%s: can't pseudo mount %s\n",
+                       sfs_Myname, export_fsname);
+       }
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(87);
+    }
+
+    /*
+     * Setup initial state of export directory
+     */
+    Export_dir.state = Exists;
+    (void) strcpy(Export_dir.file_name, testdirname);
+    Export_dir.dir = &Export_dir;
+
+#ifndef RFS
+    /*
+     * Check for and create the client directory. Stat it first, if not
+     * there then mkdir, if that fails with EEXIST we lost the race but
+     * that's OK.
+     */
+    if (Validate) {
+       (void) sprintf(testdirname, "%s", "validatedir");
+    } else {
+       (void) sprintf(testdirname, "CL%d", Client_num);
+    }
+
+    if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(88);
+    }
+
+    if (ret == 1) {
+       /*
+        * Directory doesn't exist so create it
+        * if it already exists thats OK
+        */
+        if ((ret = lad_mkdir(&file_handle, testdirname)) == -1) {
+           if (!Validate)
+               (void) generic_kill(0, SIGINT);
+           exit(89);
+        }
+       /*
+        * If someone else created this out from underneath us simply
+        * lookup the result and continue on.
+        */
+        if (ret != 0 && (ret = lad_lookup(&file_handle, testdirname)) == -1) {
+           if (!Validate)
+               (void) generic_kill(0, SIGINT);
+           exit(90);
+        }
+    }
+
+    /* testdirname now exists, verify it is a directory and writeable */
+    if (!fh_isdir(&file_handle) ||
+               (check_fh_access(&file_handle) == -1)) {
+       (void) fprintf(stderr,
+               "%s: %s is either not a directory or not accessible\n",
+                       sfs_Myname, testdirname);
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(91);
+    }
+
+    /*
+     * logically chdir into CL directory
+     */
+   /*  Export_dir = file_handle; Implied bcopy here */
+    (void) memmove(&Export_dir,&file_handle,sizeof(sfs_fh_type));
+    Export_dir.fh_data = Ex_fh_datap;
+    (void ) memmove(Export_dir.fh_data, file_handle.fh_data, 
+                       sizeof(sfs_fh_data));
+    (void) memset((char *)&file_handle, 0, sizeof(file_handle));
+    (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
+    file_handle.fh_data = fh_datap;
+    file_handle.dir = &Export_dir;
+
+    /*
+     * Validation only occurs one directory deep so we can exit early
+     */
+    if (Validate)
+        return;
+
+    (void) sprintf(testdirname, "testdir%d", dirnum);
+
+    if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
+       (void) generic_kill(0, SIGINT);
+       exit(92);
+    }
+
+    if (ret == 1) {
+       /*
+        * Directory doesn't exist so create it
+        */
+        if (lad_mkdir(&file_handle, testdirname) != 0) {
+           (void) fprintf(stderr, "%s: Unable to create %s\n",
+                       sfs_Myname, testdirname);
+           (void) generic_kill(0, SIGINT);
+           exit(93);
+        }
+    }
+
+    /* testdirname now exists, verify it is a directory and writeable */
+    if (!fh_isdir(&file_handle) ||
+               (check_fh_access(&file_handle) == -1)) {
+       (void) fprintf(stderr,
+               "%s: %s is either not a directory or not accessible\n",
+                       sfs_Myname, testdirname);
+       (void) generic_kill(0, SIGINT);
+       exit(94);
+    }
+
+    /*
+     * logically chdir into testdir directory
+     */
+    /* Export_dir = file_handle;*/
+    (void) memmove(&Export_dir, &file_handle, sizeof(struct sfs_fh_type));
+    Export_dir.fh_data = Ex_fh_datap; /* Put pointer back */
+    (void) memmove(Export_dir.fh_data, file_handle.fh_data, sizeof
+                       (sfs_fh_data));
+#endif
+} /* init_mount_point */
+
+/*
+ * Get the filehandle for 'mount_fsname', and return it
+ * Returns NULL for error ... not mounted || no NFS client.
+ *
+ * Children should only call this routine 1 time.
+ */
+CLIENT *
+lad_getmnt_hand(
+    char *             mount_point)
+{
+    char               mnt_pnt[SFS_MAXPATHLEN];    /* working buffer */
+    char               host[SFS_MAXPATHLEN];     /* host with exported fs */
+    static struct hostent      hp;
+    struct hostent     *thp;
+    CLIENT             *mount_client_ptr;      /* Mount client handle */
+    char               *cp;
+    int                        rpc_result;             /* rpc call result */
+    uint32_t           mount_vers = 0;
+
+    /*
+     * If the mount point is of the form host:path just use the explicit
+     * name instead of grovelling through the mount table.
+     */
+    (void) strcpy(mnt_pnt, mount_point);
+    cp = strchr(mnt_pnt, ':');
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, mount_point);
+       return(NULL);
+    }
+
+    *cp++ = '\0';
+    (void) strcpy(host, mnt_pnt);
+
+    /* Verify NFS Version */
+    rpc_result = callrpc(host,
+                       (uint32_t) NFS_PROGRAM,
+                       (uint32_t) nfs_version,
+                       (uint32_t) NFSPROC_NULL, (xdrproc_t) xdr_void,
+                       (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL);
+    if (rpc_result != 0) {
+        clnt_perrno((enum clnt_stat)rpc_result);
+        (void) fprintf(stderr,
+"\nUnable to contact NFS server %s.\n", host);
+        (void) fprintf(stderr,
+"Verify NFS server daemon supporting version %u is running and\n",
+               (uint32_t)nfs_version);
+        (void) fprintf(stderr, "registered with the portmapper.\n");
+       return(NULL);
+    }
+
+    /* Get host's address */
+    if ((thp = gethostbyname(host)) == NULL) {
+       /* Failure may be due to yellow pages, try again */
+       if ((thp = gethostbyname(host)) == NULL) {
+           (void) fprintf(stderr, "%s: %s not in hosts database\n",
+                           sfs_Myname, host);
+           return(NULL);
+       }
+    }
+
+    hp = *thp;
+    Server_hostent = &hp;
+
+    if (nfs_version == NFS_VERSION)
+       mount_vers = MOUNTVERS;
+    if (nfs_version == NFS_V3)
+       mount_vers = MOUNTVER3;
+
+    mount_client_ptr = lad_clnt_create(0, Server_hostent,
+                                        (uint32_t) MOUNTPROG,
+                                        mount_vers,
+                                        RPC_ANYSOCK, &Mount_timer);
+                
+
+    if (mount_client_ptr == ((CLIENT*) NULL)) {
+       (void) fprintf(stderr,
+                       "%s: portmap/mountd %s server not responding",
+                       sfs_Myname, mount_point);
+       return(NULL);
+    }
+
+    mount_client_ptr->cl_auth = authunix_create_default();
+    return (mount_client_ptr);
+
+} /* lad_getmnt_hand */
+
+
+/*
+ * Get the filehandle for 'mount_fsname', and return it in 'fh_ptr'.
+ * Returns 0 for OK, -1 for error ... not mounted || no NFS client.
+ *
+ * Children should only call this routine 1 time.
+ */
+static int
+pseudo_mount(
+    char *             mount_fsname,
+    int                        version,
+    char *             fh_ptr,
+    CLIENT *           mount_client_ptr)
+{
+    char *             host_ptr;               /* host with exported fs */
+    char *             path_ptr;               /* ptr to path for RPC */
+
+    struct fhstatus    fhs;                    /* status of mountd call */
+    nfs_fh3 *          fh_ptr3;
+    mountres3          mntres3;                /* status of mountd call */
+    char *             cp;
+    enum clnt_stat     rpc_stat;
+    int                        tries = 0;              /* Number of retries */
+                               /* Space by 200ms intervals. */
+    int                        pacesleep = Child_num * 200;
+
+    /* Parse the fsname for host and path strings */
+    cp = strchr(mount_fsname, ':');
+
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, mount_fsname);
+       return(-1);
+    }
+
+    *cp++ = '\0';
+    host_ptr = mount_fsname;
+    path_ptr = cp;
+
+    /* Check host's address */
+    if (gethostbyname(host_ptr) == NULL) {
+       /* Failure may be due to yellow pages, try again */
+       if (gethostbyname(host_ptr) == NULL) {
+           (void) fprintf(stderr, "%s: %s not in hosts database\n",
+                           sfs_Myname, host_ptr);
+           return(-1);
+       }
+    }
+
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: mount clnt_call\n", sfs_Myname);
+    }
+
+    /* get fhandle of remote path from host's mountd */
+
+retry_mount:
+    /*
+     * Many children on many clients hammer a server with
+     * mounts. Crude fix is to pace them. Some run rule interpretations
+     * are to have *many* children on each client. This can
+     * cause problems.
+     */
+    (void) msec_sleep(pacesleep);
+
+    if (version == NFS_VERSION) {
+       (void) memset((char *) &fhs, '\0', sizeof (fhs));
+       rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_path,
+                       (char *) &path_ptr,xdr_fhstatus,(char *) &fhs,
+                       Mount_timer);
+    } else if (version == NFS_V3) {
+       (void) memset((char *) &mntres3, '\0', sizeof (mntres3));
+       rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_dirpath,
+                       (char *) &path_ptr, xdr_mntres3, (char *) &mntres3,
+                       Mount_timer);
+    } else
+       rpc_stat = RPC_PROGVERSMISMATCH;
+
+    errno = 0;
+    if (rpc_stat != RPC_SUCCESS) {
+
+       switch (rpc_stat) {
+
+           case RPC_TIMEDOUT:
+               errno = ETIMEDOUT;
+               (void) fprintf(stderr,
+                   "%s: mounting %s:%s server not responding: %s (%d)\n",
+                           sfs_Myname, host_ptr, path_ptr,
+                           strerror(errno), errno);
+               if (tries++ < NUMBER_MOUNT_RETRIES) {
+                   /* Randomize the backoff on retry */
+                   pacesleep = pacesleep + (sfs_random() % 2000);
+                   goto retry_mount;
+               }
+               break;
+
+
+           case RPC_PMAPFAILURE:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s portmap call failed: %s (%d)\n",
+                           sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           case RPC_PROGNOTREGISTERED:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s nfsd not registered: %s (%d)\n",
+                           sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           case RPC_AUTHERROR:
+               errno = EACCES;
+               (void) fprintf(stderr,
+                       "%s: mounting %s authentication failed: %s (%d)\n",
+                       sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           default:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s failed: %s (%d)\n",
+                           sfs_Myname, host_ptr, path_ptr,
+                           strerror(errno), errno);
+               break;
+       }
+
+       clnt_perror(mount_client_ptr, "");
+       return(-1);
+
+    } /* MOUNTPROC_MNT call failed */
+
+    if (version == NFS_VERSION) {
+       if (fhs.fhs_status != 0) {
+           if (fhs.fhs_status == EACCES) {
+               (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
+                          sfs_Myname, host_ptr, path_ptr);
+           } else {
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s - bad fh status %d\n ",
+                           sfs_Myname, host_ptr, path_ptr, fhs.fhs_status);
+           }
+           return(-1);
+       } /* bad fhs status */
+
+       /*
+        * fill in the caller's file handle
+        */
+       (void) memmove(fh_ptr, (char *) &fhs.fhs_fh, NFS_FHSIZE);
+
+    } else if (version == NFS_V3) {
+
+       if (mntres3.fhs_status != MNT_OK) {
+           if (mntres3.fhs_status == MNT3ERR_ACCES) {
+               (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
+                          sfs_Myname, host_ptr, path_ptr);
+           } else {
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s - bad fh status %d\n ",
+                   sfs_Myname, host_ptr, path_ptr, mntres3.fhs_status);
+           }
+           return(-1);
+       } /* bad fhs status */
+
+       /*
+        * fill in the caller's file handle
+        * space pointed by fhandle3_val is allocated through xdr_mntres3
+        */
+       fh_ptr3 = (nfs_fh3 *)fh_ptr;
+       fh_ptr3->fh3_length = mntres3.mntres3_u.mntinfo.fhandle.fhandle3_len;
+       (void) memmove((char *) fh_ptr3->fh3_u.data,
+                       (char *) mntres3.mntres3_u.mntinfo.fhandle.fhandle3_val,
+                       fh_ptr3->fh3_length);
+    }
+
+    return(0);
+
+} /* pseudo_mount */
+
+
+/* sfs_c_mnt.c */
diff --git a/TBBT/trace_play/sfs_c_nfs.h b/TBBT/trace_play/sfs_c_nfs.h
new file mode 100644 (file)
index 0000000..eb34652
--- /dev/null
@@ -0,0 +1,1470 @@
+#ifndef __sfs_c_nfs_h
+#define __sfs_c_nfs_h
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * @(#)sfs_c_nfs.h     2.1     97/10/23
+ *
+ * -------------------------- sfs_c_nfs.h -------------------------
+ *
+ *     Literals and types for the NFS protocol, Version 2.
+ *
+ *.Revision_History
+ *
+ *     Richard Bean    17-May-90       Created.
+ */
+
+
+/*
+ * for RPC calls
+ */
+/* #define NFS_PORT    2049 */
+#define NFS_PROGRAM    ((uint32_t)100003)
+#define NFS_VERSION    ((uint32_t)2)
+#define NFS_V3         ((uint32_t)3)
+
+/*
+ * fixed sizes
+ */
+#define NFS_MAXDATA    8192
+//#define NFS_MAXDATA  16384
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN  255
+#define NFS_COOKIESIZE 4
+#define NFS_FHSIZE     32
+
+
+#if !defined(AIX)
+typedef struct {
+       char    data[NFS_FHSIZE];
+} fhandle_t;
+#endif  /* AIX  */
+
+/*
+ * Definition of "standard" mount parameters
+ */
+#define MOUNTPROG      100005
+#define MOUNTVERS      1
+#define MOUNTPROC_MNT  1
+
+struct fhstatus {
+        int fhs_status;
+        fhandle_t fhs_fh;
+};
+
+typedef fhandle_t nfs_fh;
+
+/*
+ * fattr modes
+ */
+/*
+ * The mode mask is used to mask off server vendor specific mode bits
+ * from the mode field.  This allows clients from different vendors to
+ * validate servers from different vendors.
+ */
+#define NFSMODE_MASK 0177777
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+
+/*
+ * NFS Procedures
+ */
+#define NFSPROC_NULL           0
+#define NFSPROC_GETATTR                1
+#define NFSPROC_SETATTR                2
+#define NFSPROC_ROOT           3
+#define NFSPROC_LOOKUP         4
+#define NFSPROC_READLINK       5
+#define NFSPROC_READ           6
+#define NFSPROC_WRITECACHE     7
+#define NFSPROC_WRITE          8
+#define NFSPROC_CREATE         9
+#define NFSPROC_REMOVE         10
+#define NFSPROC_RENAME         11
+#define NFSPROC_LINK           12
+#define NFSPROC_SYMLINK                13
+#define NFSPROC_MKDIR          14
+#define NFSPROC_RMDIR          15
+#define NFSPROC_READDIR                16
+#define NFSPROC_STATFS         17
+#define NFS_PROCEDURE_COUNT    (NFSPROC_STATFS + 1)
+
+
+/*
+ * call and return types
+ */
+enum nfsstat {
+       NFS_OK =                0,
+       NFSERR_PERM =           1,
+       NFSERR_NOENT =          2,
+       NFSERR_IO =             5,
+       NFSERR_NXIO =           6,
+       NFSERR_ACCES =          13,
+       NFSERR_EXIST =          17,
+       NFSERR_XDEV =           18,
+       NFSERR_NODEV =          19,
+       NFSERR_NOTDIR =         20,
+       NFSERR_ISDIR =          21,
+       NFSERR_INVAL =          22,
+       NFSERR_FBIG =           27,
+       NFSERR_NOSPC =          28,
+       NFSERR_ROFS =           30,
+       NFSERR_OPNOTSUPP =      45,
+       NFSERR_NAMETOOLONG =    63,
+       NFSERR_NOTEMPTY =       66,
+       NFSERR_DQUOT =          69,
+       NFSERR_STALE =          70,
+       NFSERR_REMOTE =         71,
+       NFSERR_WFLUSH =         99
+};
+typedef enum nfsstat nfsstat;
+
+
+enum ftype {
+       NFNON = 0,
+       NFREG = 1,
+       NFDIR = 2,
+       NFBLK = 3,
+       NFCHR = 4,
+       NFLNK = 5,
+       NFSOCK = 6,
+       NFBAD = 7,
+       NFFIFO = 8
+};
+typedef enum ftype ftype;
+#define NUM_TYPES 5
+
+
+struct nfstime {
+       unsigned int seconds;
+       unsigned int useconds;
+};
+typedef struct nfstime nfstime;
+
+
+struct fattr {
+       ftype type;
+       unsigned int mode;
+       unsigned int nlink;
+       unsigned int uid;
+       unsigned int gid;
+       unsigned int size;
+       unsigned int blocksize;
+       unsigned int rdev;
+       unsigned int blocks;
+       unsigned int fsid;
+       unsigned int fileid;
+       nfstime atime;
+       nfstime mtime;
+       nfstime ctime;
+};
+typedef struct fattr fattr;
+
+
+struct sattr {
+       unsigned int mode;
+       unsigned int uid;
+       unsigned int gid;
+       unsigned int size;
+       nfstime atime;
+       nfstime mtime;
+};
+typedef struct sattr sattr;
+
+
+typedef char *filename;
+
+
+typedef char *nfspath;
+
+
+struct attrstat {
+       nfsstat status;
+       union {
+               fattr attributes;
+       } attrstat_u;
+};
+typedef struct attrstat attrstat;
+
+
+struct sattrargs {
+       nfs_fh file;
+       sattr attributes;
+};
+typedef struct sattrargs sattrargs;
+
+
+struct diropargs {
+       nfs_fh dir;
+       filename name;
+};
+typedef struct diropargs diropargs;
+
+
+struct diropokres {
+       nfs_fh file;
+       fattr attributes;
+};
+typedef struct diropokres diropokres;
+
+
+struct diropres {
+       nfsstat status;
+       union {
+               diropokres diropres;
+       } diropres_u;
+};
+typedef struct diropres diropres;
+
+
+struct readlinkres {
+       nfsstat status;
+       struct {
+               nfspath data;
+               int len;        /* for convenience only, not in the protocol */
+       } readlinkres_u;
+};
+typedef struct readlinkres readlinkres;
+
+
+struct readargs {
+       nfs_fh file;
+       unsigned int offset;
+       unsigned int count;
+       unsigned int totalcount;        /* unused field, but in the protocol */
+};
+typedef struct readargs readargs;
+
+
+struct readokres {
+       fattr attributes;
+       struct {
+               unsigned int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct readokres readokres;
+
+
+struct readres {
+       nfsstat status;
+       union {
+               readokres reply;
+       } readres_u;
+};
+typedef struct readres readres;
+
+
+struct writeargs {
+       nfs_fh file;
+       unsigned int beginoffset;       /* unused field, but in the protocol */
+       unsigned int offset;
+       unsigned int totalcount;        /* unused field, but in the protocol */
+       struct {
+               unsigned int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct writeargs writeargs;
+
+
+struct createargs {
+       diropargs where;
+       sattr attributes;
+};
+typedef struct createargs createargs;
+
+
+struct renameargs {
+       diropargs from;
+       diropargs to;
+};
+typedef struct renameargs renameargs;
+
+
+struct linkargs {
+       nfs_fh from;
+       diropargs to;
+};
+typedef struct linkargs linkargs;
+
+
+struct symlinkargs {
+       diropargs from;
+       nfspath to;
+       sattr attributes;
+};
+typedef struct symlinkargs symlinkargs;
+
+
+struct mkdirargs {
+       diropargs where;
+       sattr attributes;
+};
+typedef struct mkdirargs mkdirargs;
+
+
+typedef char nfscookie[NFS_COOKIESIZE];
+
+
+struct readdirargs {
+       nfs_fh dir;
+       nfscookie cookie;
+       unsigned int count;
+};
+typedef struct readdirargs readdirargs;
+
+
+struct entry {
+       bool_t valid;   /* bool for entry is present */
+       unsigned int fileid;
+       uint16_t name_len;
+       filename name;
+       nfscookie cookie;
+};
+typedef struct entry entry;
+
+
+struct dirlist {
+       int max_entries;        /* for convenience only, not in the protocol */
+       entry *entries;         /* a stream of consecutive entry's */
+       bool_t eof;
+};
+typedef struct dirlist dirlist;
+
+
+struct readdirres {
+       nfsstat status;
+       union {
+               dirlist reply;
+       } readdirres_u;
+};
+typedef struct readdirres readdirres;
+
+
+struct statfsokres {
+       unsigned int tsize;
+       unsigned int bsize;
+       unsigned int blocks;
+       unsigned int bfree;
+       unsigned int bavail;
+};
+typedef struct statfsokres statfsokres;
+
+
+struct statfsres {
+       nfsstat status;
+       union {
+               statfsokres reply;
+       } statfsres_u;
+};
+typedef struct statfsres statfsres;
+
+
+/*
+ *     Literals and types for the NFS protocol, Version 3.
+ */
+
+
+/*
+ * for RPC calls
+ */
+
+/*
+ * fixed sizes
+ */
+#define NFS3_FHSIZE    64
+#define NFS3_COOKIEVERFSIZE    8
+#define NFS3_CREATEVERFSIZE    8
+#define NFS3_WRITEVERFSIZE     8
+
+#define nfs3nametoolong        ((char *)-1)
+
+/*
+ * Not all systems have a built in long long type so we define a
+ * special version for sfs to use.
+ */
+typedef union {
+       struct {
+               uint32_t _u;
+               uint32_t _l;
+       } _p;
+       char _f[8];
+} nfs_uint64_t;
+
+typedef char *filename3;
+
+typedef char *nfspath3;
+
+typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
+
+typedef char createverf3[NFS3_CREATEVERFSIZE];
+
+typedef char writeverf3[NFS3_WRITEVERFSIZE];
+
+struct nfs_fh3 {
+       unsigned int fh3_length;
+       union nfs_fh3_u {
+               struct {
+                       char _u[NFS_FHSIZE];
+                       char _l[NFS_FHSIZE];
+               } _p;
+               char data[NFS3_FHSIZE];
+       } fh3_u;
+};
+#define fh3_fsid       fh3_u.nfs_fh3_i.fh3_i.fh_fsid
+#define fh3_len                fh3_u.nfs_fh3_i.fh3_i.fh_len /* fid length */
+#define fh3_data       fh3_u.nfs_fh3_i.fh3_i.fh_data /* fid bytes */
+#define fh3_xlen       fh3_u.nfs_fh3_i.fh3_i.fh_xlen
+#define fh3_xdata      fh3_u.nfs_fh3_i.fh3_i.fh_xdata
+typedef struct nfs_fh3 nfs_fh3;
+
+struct diropargs3 {
+       nfs_fh3 dir;
+       filename3 name;
+};
+typedef struct diropargs3 diropargs3;
+
+struct nfstime3 {
+       uint32_t seconds;
+       uint32_t nseconds;
+};
+typedef struct nfstime3 nfstime3;
+
+struct specdata3 {
+       uint32_t specdata1;
+       uint32_t specdata2;
+};
+typedef struct specdata3 specdata3;
+
+
+/*
+ * call and return types
+ */
+enum nfsstat3 {
+       NFS3_OK = 0,
+       NFS3ERR_PERM = 1,
+       NFS3ERR_NOENT = 2,
+       NFS3ERR_IO = 5,
+       NFS3ERR_NXIO = 6,
+       NFS3ERR_ACCES = 13,
+       NFS3ERR_EXIST = 17,
+       NFS3ERR_XDEV = 18,
+       NFS3ERR_NODEV = 19,
+       NFS3ERR_NOTDIR = 20,
+       NFS3ERR_ISDIR = 21,
+       NFS3ERR_INVAL = 22,
+       NFS3ERR_FBIG = 27,
+       NFS3ERR_NOSPC = 28,
+       NFS3ERR_ROFS = 30,
+       NFS3ERR_MLINK = 31,
+       NFS3ERR_NAMETOOLONG = 63,
+       NFS3ERR_NOTEMPTY = 66,
+       NFS3ERR_DQUOT = 69,
+       NFS3ERR_STALE = 70,
+       NFS3ERR_REMOTE = 71,
+       NFS3ERR_BADHANDLE = 10001,
+       NFS3ERR_NOT_SYNC = 10002,
+       NFS3ERR_BAD_COOKIE = 10003,
+       NFS3ERR_NOTSUPP = 10004,
+       NFS3ERR_TOOSMALL = 10005,
+       NFS3ERR_SERVERFAULT = 10006,
+       NFS3ERR_BADTYPE = 10007,
+       NFS3ERR_JUKEBOX = 10008,
+       NFS3ERR_RFS_TIMEOUT = 10009,                    // RFS
+       NFS3ERR_RFS_MISS = 10010                // RFS reply missed in trace
+};
+typedef enum nfsstat3 nfsstat3;
+
+enum ftype3 {
+       NF3NON = 0,
+       NF3REG = 1,
+       NF3DIR = 2,
+       NF3BLK = 3,
+       NF3CHR = 4,
+       NF3LNK = 5,
+       NF3SOCK = 6,
+       NF3FIFO = 7
+};
+typedef enum ftype3 ftype3;
+#define NUM_TYPES 5
+
+
+struct fattr3 {
+       ftype3          type;
+       uint32_t                mode;
+       uint32_t                nlink;
+       uint32_t                uid;
+       uint32_t                gid;
+       nfs_uint64_t    size;
+       nfs_uint64_t    used;
+       specdata3       rdev;
+       nfs_uint64_t    fsid;
+       nfs_uint64_t    fileid;
+       nfstime3        atime;
+       nfstime3        mtime;
+       nfstime3        ctime;
+};
+typedef struct fattr3 fattr3;
+
+struct post_op_attr {
+       bool_t  attributes;
+       fattr3  attr;
+};
+typedef struct post_op_attr post_op_attr;
+
+struct wcc_attr {
+       nfs_uint64_t    size;
+       nfstime3        mtime;
+       nfstime3        ctime;
+};
+typedef struct wcc_attr wcc_attr;
+
+struct pre_op_attr {
+       bool_t          attributes;
+       wcc_attr        attr;
+};
+typedef struct pre_op_attr pre_op_attr;
+
+struct wcc_data {
+       pre_op_attr     before;
+       post_op_attr    after;
+};
+typedef struct wcc_data wcc_data;
+
+struct post_op_fh3 {
+       bool_t  handle_follows;
+       nfs_fh3 handle;
+};
+typedef struct post_op_fh3 post_op_fh3;
+
+enum time_how {
+       DONT_CHANGE = 0,
+       SET_TO_SERVER_TIME = 1,
+       SET_TO_CLIENT_TIME = 2
+};
+typedef enum time_how time_how;
+
+struct set_mode3 {
+       bool_t set_it;
+       uint32_t mode;
+};
+typedef struct set_mode3 set_mode3;
+
+struct set_uid3 {
+       bool_t set_it;
+       uint32_t uid;
+};
+typedef struct set_uid3 set_uid3;
+struct set_gid3 {
+       bool_t set_it;
+       uint32_t gid;
+};
+typedef struct set_gid3 set_gid3;
+struct set_size3 {
+       bool_t          set_it;
+       nfs_uint64_t    size;
+};
+typedef struct set_size3 set_size3;
+struct set_atime {
+       time_how set_it;
+       nfstime3 atime;
+};
+typedef struct set_atime set_atime;
+struct set_mtime {
+       time_how set_it;
+       nfstime3 mtime;
+};
+typedef struct set_mtime set_mtime;
+struct sattr3 {
+       set_mode3       mode;
+       set_uid3        uid;
+       set_gid3        gid;
+       set_size3       size;
+       set_atime       atime;
+       set_mtime       mtime;
+};
+typedef struct sattr3 sattr3;
+
+
+#define resok   res_u.ok
+#define resfail res_u.fail
+
+struct GETATTR3args {
+       nfs_fh3 object;
+};
+typedef struct GETATTR3args GETATTR3args;
+
+struct GETATTR3resok {
+       fattr3 obj_attributes;
+};
+typedef struct GETATTR3resok GETATTR3resok;
+
+struct GETATTR3res {
+       nfsstat3 status;
+       union {
+               GETATTR3resok ok;
+       } res_u;
+};
+typedef struct GETATTR3res GETATTR3res;
+
+struct sattrguard3 {
+       bool_t          check;
+       nfstime3        obj_ctime;
+};
+typedef struct sattrguard3 sattrguard3;
+
+struct SETATTR3args {
+       nfs_fh3         object;
+       sattr3          new_attributes;
+       sattrguard3     guard;
+};
+typedef struct SETATTR3args SETATTR3args;
+
+struct SETATTR3resok {
+       wcc_data obj_wcc;
+};
+typedef struct SETATTR3resok SETATTR3resok;
+
+struct SETATTR3resfail {
+       wcc_data obj_wcc;
+};
+typedef struct SETATTR3resfail SETATTR3resfail;
+
+struct SETATTR3res {
+       nfsstat3 status;
+       union {
+               SETATTR3resok   ok;
+               SETATTR3resfail fail;
+       } res_u;
+};
+typedef struct SETATTR3res SETATTR3res;
+
+struct LOOKUP3args {
+       diropargs3 what;
+};
+typedef struct LOOKUP3args LOOKUP3args;
+
+struct LOOKUP3resok {
+       nfs_fh3         object;
+       post_op_attr    obj_attributes;
+       post_op_attr    dir_attributes;
+};
+typedef struct LOOKUP3resok LOOKUP3resok;
+
+struct LOOKUP3resfail {
+       post_op_attr dir_attributes;
+};
+typedef struct LOOKUP3resfail LOOKUP3resfail;
+
+struct LOOKUP3res {
+       nfsstat3 status;
+       union {
+               LOOKUP3resok    ok;
+               LOOKUP3resfail  fail;
+       } res_u;
+};
+typedef struct LOOKUP3res LOOKUP3res;
+
+struct ACCESS3args {
+       nfs_fh3 object;
+       uint32_t        access;
+};
+typedef struct ACCESS3args ACCESS3args;
+#define ACCESS3_READ   0x1
+#define ACCESS3_LOOKUP 0x2
+#define ACCESS3_MODIFY 0x4
+#define ACCESS3_EXTEND 0x8
+#define ACCESS3_DELETE 0x10
+#define ACCESS3_EXECUTE 0x20
+
+struct ACCESS3resok {
+       post_op_attr obj_attributes;
+       uint32_t access;
+};
+typedef struct ACCESS3resok ACCESS3resok;
+
+struct ACCESS3resfail {
+       post_op_attr obj_attributes;
+};
+typedef struct ACCESS3resfail ACCESS3resfail;
+
+struct ACCESS3res {
+       nfsstat3 status;
+       union {
+               ACCESS3resok    ok;
+               ACCESS3resfail  fail;
+       } res_u;
+};
+typedef struct ACCESS3res ACCESS3res;
+
+struct READLINK3args {
+       nfs_fh3 symlink;
+};
+typedef struct READLINK3args READLINK3args;
+
+struct READLINK3resok {
+       post_op_attr    symlink_attributes;
+       nfspath3        data;
+};
+typedef struct READLINK3resok READLINK3resok;
+
+struct READLINK3resfail {
+       post_op_attr symlink_attributes;
+};
+typedef struct READLINK3resfail READLINK3resfail;
+
+struct READLINK3res {
+       nfsstat3 status;
+       union {
+               READLINK3resok          ok;
+               READLINK3resfail        fail;
+       } res_u;
+};
+typedef struct READLINK3res READLINK3res;
+
+struct READ3args {
+       nfs_fh3         file;
+       nfs_uint64_t    offset;
+       uint32_t                count;
+};
+typedef struct READ3args READ3args;
+
+struct READ3resok {
+       post_op_attr file_attributes;
+       uint32_t count;
+       bool_t eof;
+       struct {
+               unsigned int data_len;
+               char *data_val;
+       } data;
+       unsigned int size;
+};
+typedef struct READ3resok READ3resok;
+
+struct READ3resfail {
+       post_op_attr file_attributes;
+};
+typedef struct READ3resfail READ3resfail;
+
+struct READ3res {
+       nfsstat3 status;
+       union {
+               READ3resok ok;
+               READ3resfail fail;
+       } res_u;
+};
+typedef struct READ3res READ3res;
+
+enum stable_how {
+       UNSTABLE = 0,
+       DATA_SYNC = 1,
+       FILE_SYNC = 2
+};
+typedef enum stable_how stable_how;
+
+struct WRITE3args {
+       nfs_fh3 file;
+       nfs_uint64_t offset;
+       uint32_t count;
+       stable_how stable;
+       struct {
+               unsigned int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct WRITE3args WRITE3args;
+
+struct WRITE3resok {
+       wcc_data file_wcc;
+       uint32_t count;
+       stable_how committed;
+       writeverf3 verf;
+};
+typedef struct WRITE3resok WRITE3resok;
+
+struct WRITE3resfail {
+       wcc_data file_wcc;
+};
+typedef struct WRITE3resfail WRITE3resfail;
+
+struct WRITE3res {
+       nfsstat3 status;
+       union {
+               WRITE3resok ok;
+               WRITE3resfail fail;
+       } res_u;
+};
+typedef struct WRITE3res WRITE3res;
+
+enum createmode3 {
+       UNCHECKED = 0,
+       GUARDED = 1,
+       EXCLUSIVE = 2
+};
+typedef enum createmode3 createmode3;
+
+struct createhow3 {
+       createmode3 mode;
+       union {
+               sattr3 obj_attributes;
+               createverf3 verf;
+       } createhow3_u;
+};
+typedef struct createhow3 createhow3;
+
+struct CREATE3args {
+       diropargs3 where;
+       createhow3 how;
+};
+typedef struct CREATE3args CREATE3args;
+
+struct CREATE3resok {
+       post_op_fh3 obj;
+       post_op_attr obj_attributes;
+       wcc_data dir_wcc;
+};
+typedef struct CREATE3resok CREATE3resok;
+
+struct CREATE3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct CREATE3resfail CREATE3resfail;
+
+struct CREATE3res {
+       nfsstat3 status;
+       union {
+               CREATE3resok ok;
+               CREATE3resfail fail;
+       } res_u;
+};
+typedef struct CREATE3res CREATE3res;
+
+struct MKDIR3args {
+       diropargs3 where;
+       sattr3 attributes;
+};
+typedef struct MKDIR3args MKDIR3args;
+
+struct MKDIR3resok {
+       post_op_fh3 obj;
+       post_op_attr obj_attributes;
+       wcc_data dir_wcc;
+};
+typedef struct MKDIR3resok MKDIR3resok;
+
+struct MKDIR3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct MKDIR3resfail MKDIR3resfail;
+
+struct MKDIR3res {
+       nfsstat3 status;
+       union {
+               MKDIR3resok ok;
+               MKDIR3resfail fail;
+       } res_u;
+};
+typedef struct MKDIR3res MKDIR3res;
+
+struct symlinkdata3 {
+       sattr3 symlink_attributes;
+       nfspath3 symlink_data;
+};
+typedef struct symlinkdata3 symlinkdata3;
+
+struct SYMLINK3args {
+       diropargs3 where;
+       symlinkdata3 symlink;
+};
+typedef struct SYMLINK3args SYMLINK3args;
+
+struct SYMLINK3resok {
+       post_op_fh3 obj;
+       post_op_attr obj_attributes;
+       wcc_data dir_wcc;
+};
+typedef struct SYMLINK3resok SYMLINK3resok;
+
+struct SYMLINK3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct SYMLINK3resfail SYMLINK3resfail;
+
+struct SYMLINK3res {
+       nfsstat3 status;
+       union {
+               SYMLINK3resok ok;
+               SYMLINK3resfail fail;
+       } res_u;
+};
+typedef struct SYMLINK3res SYMLINK3res;
+
+struct devicedata3 {
+       sattr3 dev_attributes;
+       specdata3 spec;
+};
+typedef struct devicedata3 devicedata3;
+
+struct mknoddata3 {
+       ftype3 type;
+       union {
+               devicedata3 device;
+               sattr3 pipe_attributes;
+       } mknoddata3_u;
+};
+typedef struct mknoddata3 mknoddata3;
+
+struct MKNOD3args {
+       diropargs3 where;
+       mknoddata3 what;
+};
+typedef struct MKNOD3args MKNOD3args;
+
+struct MKNOD3resok {
+       post_op_fh3 obj;
+       post_op_attr obj_attributes;
+       wcc_data dir_wcc;
+};
+typedef struct MKNOD3resok MKNOD3resok;
+
+struct MKNOD3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct MKNOD3resfail MKNOD3resfail;
+
+struct MKNOD3res {
+       nfsstat3 status;
+       union {
+               MKNOD3resok ok;
+               MKNOD3resfail fail;
+       } res_u;
+};
+typedef struct MKNOD3res MKNOD3res;
+
+struct REMOVE3args {
+       diropargs3 object;
+};
+typedef struct REMOVE3args REMOVE3args;
+
+struct REMOVE3resok {
+       wcc_data dir_wcc;
+};
+typedef struct REMOVE3resok REMOVE3resok;
+
+struct REMOVE3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct REMOVE3resfail REMOVE3resfail;
+
+struct REMOVE3res {
+       nfsstat3 status;
+       union {
+               REMOVE3resok ok;
+               REMOVE3resfail fail;
+       } res_u;
+};
+typedef struct REMOVE3res REMOVE3res;
+
+struct RMDIR3args {
+       diropargs3 object;
+};
+typedef struct RMDIR3args RMDIR3args;
+
+struct RMDIR3resok {
+       wcc_data dir_wcc;
+};
+typedef struct RMDIR3resok RMDIR3resok;
+
+struct RMDIR3resfail {
+       wcc_data dir_wcc;
+};
+typedef struct RMDIR3resfail RMDIR3resfail;
+
+struct RMDIR3res {
+       nfsstat3 status;
+       union {
+               RMDIR3resok ok;
+               RMDIR3resfail fail;
+       } res_u;
+};
+typedef struct RMDIR3res RMDIR3res;
+
+struct RENAME3args {
+       diropargs3 from;
+       diropargs3 to;
+};
+typedef struct RENAME3args RENAME3args;
+
+struct RENAME3resok {
+       wcc_data fromdir_wcc;
+       wcc_data todir_wcc;
+};
+typedef struct RENAME3resok RENAME3resok;
+
+struct RENAME3resfail {
+       wcc_data fromdir_wcc;
+       wcc_data todir_wcc;
+};
+typedef struct RENAME3resfail RENAME3resfail;
+
+struct RENAME3res {
+       nfsstat3 status;
+       union {
+               RENAME3resok ok;
+               RENAME3resfail fail;
+       } res_u;
+};
+typedef struct RENAME3res RENAME3res;
+
+struct LINK3args {
+       nfs_fh3 file;
+       diropargs3 link;
+};
+typedef struct LINK3args LINK3args;
+
+struct LINK3resok {
+       post_op_attr file_attributes;
+       wcc_data linkdir_wcc;
+};
+typedef struct LINK3resok LINK3resok;
+
+struct LINK3resfail {
+       post_op_attr file_attributes;
+       wcc_data linkdir_wcc;
+};
+typedef struct LINK3resfail LINK3resfail;
+
+struct LINK3res {
+       nfsstat3 status;
+       union {
+               LINK3resok ok;
+               LINK3resfail fail;
+       } res_u;
+};
+typedef struct LINK3res LINK3res;
+
+struct READDIR3args {
+       nfs_fh3 dir;
+       nfs_uint64_t cookie;
+       cookieverf3 cookieverf;
+       uint32_t count;
+};
+typedef struct READDIR3args READDIR3args;
+
+struct entry3 {
+       nfs_uint64_t fileid;
+       char name[SFS_MAXNAMLEN];
+       nfs_uint64_t cookie;
+};
+typedef struct entry3 entry3;
+
+struct dirlist3 {
+       entry3 *entries;
+       bool_t eof;
+};
+typedef struct dirlist3 dirlist3;
+
+struct READDIR3resok {
+       post_op_attr dir_attributes;
+       cookieverf3 cookieverf;
+       dirlist3 reply;
+       unsigned int size;
+       unsigned int count;
+       nfs_uint64_t cookie;
+};
+typedef struct READDIR3resok READDIR3resok;
+
+struct READDIR3resfail {
+       post_op_attr dir_attributes;
+};
+typedef struct READDIR3resfail READDIR3resfail;
+
+struct READDIR3res {
+       nfsstat3 status;
+       union {
+               READDIR3resok ok;
+               READDIR3resfail fail;
+       } res_u;
+};
+typedef struct READDIR3res READDIR3res;
+
+struct READDIRPLUS3args {
+       nfs_fh3 dir;
+       nfs_uint64_t cookie;
+       cookieverf3 cookieverf;
+       uint32_t dircount;
+       uint32_t maxcount;
+};
+typedef struct READDIRPLUS3args READDIRPLUS3args;
+
+struct entryplus3 {
+       nfs_uint64_t fileid;
+       char name[SFS_MAXNAMLEN];
+       nfs_uint64_t cookie;
+       post_op_attr name_attributes;
+       post_op_fh3 name_handle;
+};
+typedef struct entryplus3 entryplus3;
+
+struct dirlistplus3 {
+       entryplus3 *entries;
+       bool_t eof;
+};
+typedef struct dirlistplus3 dirlistplus3;
+
+struct READDIRPLUS3resok {
+       post_op_attr dir_attributes;
+       cookieverf3 cookieverf;
+       dirlistplus3 reply;
+       unsigned int size;
+       unsigned int count;
+       unsigned int maxcount;
+       post_op_attr *attributes;
+       post_op_fh3 *handles;
+};
+typedef struct READDIRPLUS3resok READDIRPLUS3resok;
+
+struct READDIRPLUS3resfail {
+       post_op_attr dir_attributes;
+};
+typedef struct READDIRPLUS3resfail READDIRPLUS3resfail;
+
+struct READDIRPLUS3res {
+       nfsstat3 status;
+       union {
+               READDIRPLUS3resok ok;
+               READDIRPLUS3resfail fail;
+       } res_u;
+};
+typedef struct READDIRPLUS3res READDIRPLUS3res;
+
+struct FSSTAT3args {
+       nfs_fh3 fsroot;
+};
+typedef struct FSSTAT3args FSSTAT3args;
+
+struct FSSTAT3resok {
+       post_op_attr obj_attributes;
+       nfs_uint64_t tbytes;
+       nfs_uint64_t fbytes;
+       nfs_uint64_t abytes;
+       nfs_uint64_t tfiles;
+       nfs_uint64_t ffiles;
+       nfs_uint64_t afiles;
+       uint32_t invarsec;
+};
+typedef struct FSSTAT3resok FSSTAT3resok;
+
+struct FSSTAT3resfail {
+       post_op_attr obj_attributes;
+};
+typedef struct FSSTAT3resfail FSSTAT3resfail;
+
+struct FSSTAT3res {
+       nfsstat3 status;
+       union {
+               FSSTAT3resok ok;
+               FSSTAT3resfail fail;
+       } res_u;
+};
+typedef struct FSSTAT3res FSSTAT3res;
+
+struct FSINFO3args {
+       nfs_fh3 fsroot;
+};
+typedef struct FSINFO3args FSINFO3args;
+
+struct FSINFO3resok {
+       post_op_attr obj_attributes;
+       uint32_t rtmax;
+       uint32_t rtpref;
+       uint32_t rtmult;
+       uint32_t wtmax;
+       uint32_t wtpref;
+       uint32_t wtmult;
+       uint32_t dtpref;
+       nfs_uint64_t maxfilesize;
+       nfstime3 time_delta;
+       uint32_t properties;
+};
+typedef struct FSINFO3resok FSINFO3resok;
+
+struct FSINFO3resfail {
+       post_op_attr obj_attributes;
+};
+typedef struct FSINFO3resfail FSINFO3resfail;
+#define FSF3_LINK 0x1
+#define FSF3_SYMLINK 0x2
+#define FSF3_HOMOGENEOUS 0x8
+#define FSF3_CANSETTIME 0x10
+
+struct FSINFO3res {
+       nfsstat3 status;
+       union {
+               FSINFO3resok ok;
+               FSINFO3resfail fail;
+       } res_u;
+};
+typedef struct FSINFO3res FSINFO3res;
+
+struct PATHCONF3args {
+       nfs_fh3 object;
+};
+typedef struct PATHCONF3args PATHCONF3args;
+
+struct PATHCONF3resok {
+       post_op_attr obj_attributes;
+       uint32_t link_max;
+       uint32_t name_max;
+       bool_t no_trunc;
+       bool_t chown_restricted;
+       bool_t case_insensitive;
+       bool_t case_preserving;
+};
+typedef struct PATHCONF3resok PATHCONF3resok;
+
+struct PATHCONF3resfail {
+       post_op_attr obj_attributes;
+};
+typedef struct PATHCONF3resfail PATHCONF3resfail;
+
+struct PATHCONF3res {
+       nfsstat3 status;
+       union {
+               PATHCONF3resok ok;
+               PATHCONF3resfail fail;
+       } res_u;
+};
+typedef struct PATHCONF3res PATHCONF3res;
+
+struct COMMIT3args {
+       nfs_fh3 file;
+       nfs_uint64_t offset;
+       uint32_t count;
+};
+typedef struct COMMIT3args COMMIT3args;
+
+struct COMMIT3resok {
+       wcc_data file_wcc;
+       writeverf3 verf;
+};
+typedef struct COMMIT3resok COMMIT3resok;
+
+struct COMMIT3resfail {
+       wcc_data file_wcc;
+};
+typedef struct COMMIT3resfail COMMIT3resfail;
+
+struct COMMIT3res {
+       nfsstat3 status;
+       union {
+               COMMIT3resok ok;
+               COMMIT3resfail fail;
+       } res_u;
+};
+typedef struct COMMIT3res COMMIT3res;
+
+/*
+ * NFS Procedures
+ */
+#define NFSPROC3_NULL          0
+#define NFSPROC3_GETATTR       1
+#define NFSPROC3_SETATTR       2
+#define NFSPROC3_LOOKUP                3
+#define NFSPROC3_ACCESS                4
+#define NFSPROC3_READLINK      5
+#define NFSPROC3_READ          6
+#define NFSPROC3_WRITE         7
+#define NFSPROC3_CREATE                8
+#define NFSPROC3_MKDIR         9
+#define NFSPROC3_SYMLINK       10
+#define NFSPROC3_MKNOD         11
+#define NFSPROC3_REMOVE                12
+#define NFSPROC3_RMDIR         13
+#define NFSPROC3_RENAME                14
+#define NFSPROC3_LINK          15
+#define NFSPROC3_READDIR       16
+#define NFSPROC3_READDIRPLUS   17
+#define NFSPROC3_FSSTAT                18
+#define NFSPROC3_FSINFO                19
+#define NFSPROC3_PATHCONF      20
+#define NFSPROC3_COMMIT                21
+#define NFS3_PROCEDURE_COUNT   (NFSPROC3_COMMIT + 1)
+
+
+/*
+ *     mount.h definitions
+ */
+#define MOUNTVER3      ((uint32_t)3)
+#define        MNTPATHLEN 1024
+#define        MNTNAMLEN 255
+
+#define MOUNTPROC_NULL ((uint32_t)(0))
+#define MOUNTPROC_DUMP ((uint32_t)(2))
+#define MOUNTPROC_UMNT ((uint32_t)(3))
+#define MOUNTPROC_UMNTALL ((uint32_t)(4))
+#define MOUNTPROC_EXPORT ((uint32_t)(5))
+#define MOUNTPROC_EXPORTALL ((uint32_t)(6))
+#define MOUNTPROC_PATHCONF ((uint32_t)(7))
+
+struct fhandle3 {
+       unsigned int    fhandle3_len;
+       char    *fhandle3_val;
+};
+typedef struct fhandle3 fhandle3;
+
+enum mntstat3 {
+       MNT_OK = 0,
+       MNT3ERR_PERM = 1,
+       MNT3ERR_NOENT = 2,
+       MNT3ERR_IO = 5,
+       MNT3ERR_ACCES = 13,
+       MNT3ERR_NOTDIR = 20,
+       MNT3ERR_INVAL = 22,
+       MNT3ERR_NAMETOOLONG = 63,
+       MNT3ERR_NOTSUPP = 10004,
+       MNT3ERR_SERVERFAULT = 10006
+};
+typedef enum mntstat3 mntstat3;
+
+struct mntres3_ok {
+       fhandle3 fhandle;
+       struct {
+               unsigned int auth_flavors_len;
+               int *auth_flavors_val;
+       } auth_flavors;
+};
+typedef struct mntres3_ok mntres3_ok;
+
+struct mountres3 {
+       mntstat3 fhs_status;
+       union {
+               mntres3_ok mntinfo;
+       } mntres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+
+/*
+ * External XDR functions
+ */
+
+/*
+ * Mount protocol
+ */
+extern bool_t xdr_path(XDR *, char **);
+extern bool_t xdr_fhstatus(XDR *, struct fhstatus *);
+extern bool_t xdr_dirpath(XDR *, dirpath *);
+extern bool_t xdr_mntres3(XDR *, mountres3 *);
+
+/*
+ * V2
+ */
+extern bool_t xdr_create(XDR *, char *);
+extern bool_t xdr_getattr(XDR *xdrs, char *);
+extern bool_t xdr_link(XDR *xdrs, char *);
+extern bool_t xdr_lookup(XDR *xdrs, char *);
+extern bool_t xdr_mkdir(XDR *xdrs, char *);
+extern bool_t xdr_read(XDR *xdrs, char *);
+extern bool_t xdr_readdir(XDR *xdrs,  char *);
+extern bool_t xdr_readlink(XDR *xdrs, char *);
+extern bool_t xdr_remove(XDR *xdrs, char *);
+extern bool_t xdr_rename(XDR *xdrs, char *);
+extern bool_t xdr_rmdir(XDR *xdrs, char *);
+extern bool_t xdr_setattr(XDR *xdrs, char *);
+extern bool_t xdr_statfs(XDR *xdrs, char *);
+extern bool_t xdr_symlink(XDR *xdrs, char *);
+extern bool_t xdr_write(XDR *xdrs, char *);
+
+/*
+ * V3
+ */
+extern bool_t xdr_GETATTR3args(XDR *, GETATTR3args *);
+extern bool_t xdr_GETATTR3res(XDR *, GETATTR3res *);
+extern bool_t xdr_SETATTR3args(XDR *, SETATTR3args *);
+extern bool_t xdr_SETATTR3res(XDR *, SETATTR3res *);
+extern bool_t xdr_LOOKUP3args(XDR *, LOOKUP3args *);
+extern bool_t xdr_LOOKUP3res(XDR *, LOOKUP3res *);
+extern bool_t xdr_ACCESS3args(XDR *, ACCESS3args *);
+extern bool_t xdr_ACCESS3res(XDR *, ACCESS3res *);
+extern bool_t xdr_READLINK3args(XDR *, READLINK3args *);
+extern bool_t xdr_READLINK3res(XDR *, READLINK3res *);
+extern bool_t xdr_READ3args(XDR *, READ3args *);
+extern bool_t xdr_READ3res(XDR *, READ3res *);
+extern bool_t xdr_WRITE3args(XDR *, WRITE3args *);
+extern bool_t xdr_WRITE3res(XDR *, WRITE3res *);
+extern bool_t xdr_CREATE3args(XDR *, CREATE3args *);
+extern bool_t xdr_CREATE3res(XDR *, CREATE3res *);
+extern bool_t xdr_MKDIR3args(XDR *, MKDIR3args *);
+extern bool_t xdr_MKDIR3res(XDR *, MKDIR3res *);
+extern bool_t xdr_SYMLINK3args(XDR *, SYMLINK3args *);
+extern bool_t xdr_SYMLINK3res(XDR *, SYMLINK3res *);
+extern bool_t xdr_MKNOD3args(XDR *, MKNOD3args *);
+extern bool_t xdr_MKNOD3res(XDR *, MKNOD3res *);
+extern bool_t xdr_REMOVE3args(XDR *, REMOVE3args *);
+extern bool_t xdr_REMOVE3res(XDR *, REMOVE3res *);
+extern bool_t xdr_RMDIR3args(XDR *, RMDIR3args *);
+extern bool_t xdr_RMDIR3res(XDR *, RMDIR3res *);
+extern bool_t xdr_RENAME3args(XDR *, RENAME3args *);
+extern bool_t xdr_RENAME3res(XDR *, RENAME3res *);
+extern bool_t xdr_LINK3args(XDR *, LINK3args *);
+extern bool_t xdr_LINK3res(XDR *, LINK3res *);
+extern bool_t xdr_READDIR3args(XDR *, READDIR3args *);
+extern bool_t xdr_READDIR3res(XDR *, READDIR3res *);
+extern bool_t xdr_READDIRPLUS3args(XDR *, READDIRPLUS3args *);
+extern bool_t xdr_READDIRPLUS3res(XDR *, READDIRPLUS3res *);
+extern bool_t xdr_FSSTAT3args(XDR *, FSSTAT3args *);
+extern bool_t xdr_FSSTAT3res(XDR *, FSSTAT3res *);
+extern bool_t xdr_FSINFO3args(XDR *, FSINFO3args *);
+extern bool_t xdr_FSINFO3res(XDR *, FSINFO3res *);
+extern bool_t xdr_PATHCONF3args(XDR *, PATHCONF3args *);
+extern bool_t xdr_PATHCONF3res(XDR *, PATHCONF3res *);
+extern bool_t xdr_COMMIT3args(XDR *, COMMIT3args *);
+extern bool_t xdr_COMMIT3res(XDR *, COMMIT3res *);
+
+
+#endif  /* __sfs_c_nfs_h */
diff --git a/TBBT/trace_play/sfs_c_pnt.c b/TBBT/trace_play/sfs_c_pnt.c
new file mode 100644 (file)
index 0000000..cab4f43
--- /dev/null
@@ -0,0 +1,1163 @@
+#ifndef lint
+static char sfs_c_pntSid[] = "@(#)sfs_c_pnt.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *
+ *.Exported_Routines
+ *     void parent(int, int, char *, char *)
+ *
+ *.Local_Routines
+ *     void synchronize_children(int)
+ *     int signal_Prime_Client(char *, char *)
+ *     void collect_counters(int)
+ *     int check_parameters(char *, char *, int)
+ *     int check_counters(void)
+ *     void print_results(int, int, char *, int, int, char *)
+ *
+ *.Revision_History
+ *     10-Jan-92       Teelucksingh
+ *                             Client passes standard deviation compute
+ *                             values to Prime-Client as well as an
+ *                             "INVALID RUN" flag.
+ *
+ *     16-Dec-91       Wittle          Created.
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+#if !defined(_XOPEN_SOURCE)
+#include <sys/socket.h>
+#else
+#define        AF_INET         2
+#endif
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+/* forward definitions for local routines */
+static void synchronize_children(int);
+static int signal_Prime_Client(char *, char *);
+static void collect_counters(int);
+static int check_parameters(char *, char *, int);
+static int check_counters(void);
+static void print_results(int, int, char *, int, int, char *);
+static void sfs_reaper(int);
+
+/* Aggregate results storage */
+static char Client_results[(NOPS+3)*MAX_LINE_LEN];
+
+/*
+ * -------------------------  SFS Parent Code  -------------------------
+ */
+
+/*
+ * Parent: wait for kids to get ready, start them, wait for them to
+ * finish, read and accumulate results.
+ */
+void
+parent(
+    int                children,
+    int                load,
+    char *     mix_file,
+    char *     iodist_file)
+{
+    char       string[80];     /* for interactive startup */
+    int                result;
+    int                invalid_run;    /* holds INVALID RUN status */
+    int                runtime_val;    /* store Runtime value to be printed later */
+    int                Saveerrno;
+    char       *nameptr;
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    struct sigaction sig_act, old_sig_act;
+#endif
+
+    /*
+     * Setup a SIGCHLD handler in case one of our beloved children dies
+     * before its time.
+     */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    /* use XOPEN signal handling */
+
+    sig_act.sa_handler = sfs_reaper;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+    if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+        perror("sigaction failed: SIGCHLD");
+        exit(66);
+    }
+#else
+    (void) signal(SIGCHLD, sfs_reaper);
+#endif
+
+    /* Change my name for error logging */
+    if ((nameptr = strrchr(sfs_Myname, '/')) != NULL)
+        sfs_Myname = ++nameptr;
+
+    /*
+     * store the Runtime value; to be printed in results
+     */
+    if (Prime_client)
+       runtime_val = Runtime - MULTICLIENT_OFFSET;
+    else runtime_val = Runtime;
+
+    /* print logfile header information */
+    (void) fprintf(stdout,"\n");
+    (void) fprintf(stdout,
+    "************************************************************************");
+    (void) fprintf(stdout,"\n");
+    (void) fflush(stdout);
+
+    /* print sfs information */
+    if (Prime_client) {
+       (void) fprintf(stderr,
+               "\nSFS NFS Version %d Benchmark Client Logfile, %s\n",
+                       nfs_version, lad_timestamp());
+       (void) fprintf(stderr, "\tClient hostname = %s\n", lad_hostname);
+       (void) fprintf(stderr, "\tPrime Client hostname = %s\n",
+                       Prime_client);
+    }
+
+    (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
+                               SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fprintf(stderr, "NFS Protocol Version %d\n", nfs_version);
+
+    /* mount test directories */
+    (void) fprintf(stderr, "%s Mounting %d remote test directories.\n",
+               lad_timestamp(), children);
+    synchronize_children(children);
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done mounting
+     * test directories.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                      "%s Sending DONE-MOUNT message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL", ""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+               "%s:  error %d sending DONE-MOUNT message to Prime Client\n",
+               sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(67);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(68);
+       }
+
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Waiting on DO-INIT message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for DO-INIT message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send DONE-MOUNT and got DO-INIT message */
+
+    /* initialize test directories */
+    (void) fprintf(stderr, "\n");
+    (void) fprintf(stderr, "%s Initializing test directories.\n",
+                   lad_timestamp());
+
+    /* send SIGUSR1 to child processes */
+    (void) generic_kill(0, SIGUSR1);
+    synchronize_children(children);
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+    (void) fflush(stderr);
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done initializing
+     * and wait for synchronized do warmupmessage.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Sending DONE-INIT message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending DONE-INIT message to Prime Client\n",
+                   sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(69);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(70);
+       }
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                 "%s Waiting on DO-WARMUP message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for DO-WARMUP message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send DONE-INIT and got DO-WARMUP message */
+
+    if (Populate_only) {
+       (void) fprintf(stderr, "\nPopulating directories and exiting.\n");
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       sig_act.sa_handler = SIG_DFL;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+       if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGCHLD");
+           exit(71);
+       }
+#else
+       (void) signal(SIGCHLD, SIG_DFL);
+#endif
+       (void) generic_kill(0, SIGUSR1);
+       while (wait((int *) 0) != -1) {
+           /* nop */
+       }
+       return;
+    }
+
+    /* do warm-up */
+    if (Warmuptime) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "%s Performing %d seconds pretest warmup.\n",
+               lad_timestamp(), Warmuptime);
+       (void) generic_kill(0, SIGUSR1);
+       (void) sleep(Warmuptime);
+       (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+       (void) fflush(stderr);
+    }
+
+    if (Interactive) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "Hit <return> when ready to start test ...");
+       (void) fgets(string,10,stdin);
+    }
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done warm-up
+     * and wait for synchronized Start message.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                       "%s Sending READY message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending READY message to Prime Client\n",
+                   sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(72);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(73);
+       }
+
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Waiting on START message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for START message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send READY and got START message */
+
+    (void) fprintf(stderr, "\n");
+    if (Timed_run) {
+       if (Prime_client) {
+           (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
+                   lad_timestamp(), Runtime - MULTICLIENT_OFFSET);
+       } else {
+           (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
+                   lad_timestamp(), Runtime);
+       }
+    } else {
+       (void) fprintf(stderr, "%s Starting %d call test run.\n",
+               lad_timestamp(), Ops[TOTAL].target_calls);
+    }
+    (void) fflush(stderr);
+
+    /* signal child processes to go */
+    (void) generic_kill(0, SIGUSR1);
+
+    if (Timed_run)
+       (void) sleep(Runtime);
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    sig_act.sa_handler = SIG_DFL;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+    if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+        perror("sigaction failed: SIGCHLD");
+        exit(74);
+    }
+#else
+    (void) signal(SIGCHLD, SIG_DFL);
+#endif
+
+    if (Timed_run) {
+       /*
+        * The parent and the prime are both sleeping for Runtime.
+        * If the parent wakes up first, he'll tell the children to stop.
+        * If the prime wakes up first, he'll send an SIGALRM (via syncd)
+        * to the parent.  That alarm may arrive while the parent is still
+        * asleep, which is ok, or after he has starting running.  Since
+        * the parent SIGARLM catcher does nothing, there is no harm done
+        * by the extra signal in this case.
+        *
+        * Perhaps, if running multi we should just wait (pause()) for
+        * the STOP signal, like we waited for the start signal.  It would
+        * be more obvious.  The only drawback is the OTW rpc delay in
+        * receiving the stop signal from the prime.
+        */
+       (void) generic_kill(0, SIGUSR2); /* tell children to finish */
+    }
+
+    /* Wait for all the children to finish/die */
+    while (wait((int *) 0) != -1) {
+       /* nop */
+    }
+
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+    (void) fflush(stdout);
+    (void) fflush(stderr);
+
+    /* Initialize and sum up counters */
+    collect_counters(children);
+    if ((invalid_run = check_counters()) == 0)
+       invalid_run = check_parameters(iodist_file, mix_file, runtime_val);
+
+    /* print test results */
+    print_results(children, load, mix_file,
+                 invalid_run, runtime_val, iodist_file);
+
+    /*
+     * if multi-client execution then tell Prime client that
+     * I'm done with 'real' work and wait for move-data message
+     * and send data across
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr,
+                       "%s Sending DONE-TEST message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending DONE-TEST message to Prime Client\n",
+                   sfs_Myname, result);
+           errno = Saveerrno;
+           perror("signal_Prime_Client");
+           /* cleanup and exit */
+           (void) generic_kill(0, SIGINT);
+           exit(75);
+       }
+
+       /*
+        * wait for MOVE-DATA message from Prime Client before
+        * sending send results.
+        */
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+               "%s Waiting on MOVE-DATA message from Prime Client(%s).\n",
+               lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.", lad_timestamp());
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "%s Sending results to Prime Client(%s)\n",
+               lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+
+       if ((result = (int) signal_Prime_Client("CLIENT_DATA",
+           Client_results)) == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s: error %d sending client's result to Prime Client\n",
+                   sfs_Myname, result);
+           errno = Saveerrno;
+           perror("signal_Prime_Client");
+           /* cleanup and exit */
+           (void) generic_kill(0, SIGINT);
+           exit(76);
+       }
+    } /* sent done, got move-data and sent data */
+
+    (void) fprintf(stdout,"\n");
+    (void) fprintf(stdout,
+    "************************************************************************");
+    (void) fprintf(stdout,"\n");
+
+} /* parent */
+
+
+/*
+ * ------------------------  Utility Routines  --------------------------
+ */
+
+
+/*
+ * Monitor Logfile until its size reaches 'children' bytes.
+ * This means that all of the children are waiting for the next instruction.
+ */
+static void
+synchronize_children(
+    int                children)
+{
+    struct stat        statb;  /* for fstat */
+
+    do {
+       (void) sleep(1);
+       if (fstat(Log_fd, &statb) == -1) {
+           (void) fprintf(stderr, "%s: can't stat log %s", sfs_Myname, Logname);
+           (void) generic_kill(0, SIGINT);
+           exit(77);
+       }
+    } while (statb.st_size < children);
+
+    /*
+     * Truncate the log file
+     */
+    (void)close(Log_fd);
+    Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
+    if (Log_fd == -1) {
+       (void) fprintf(stderr, "%s: can't truncate log %s",
+                               sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(78);
+    }
+
+}  /* synchronize_children */
+
+
+/*
+ * Multi-client execution support routine.
+ * Call remote procedure on Prime client
+ * to send message to sfs_prime_clnt program.
+ * The message will contain a type field set to 'type',
+ * and a data field set to 'data'.
+ */
+static int
+signal_Prime_Client(
+    char *             type,
+    char *             data)
+{
+    static CLIENT *    clnt_handle = NULL;
+    static int         transaction_id = 0;
+    int *              result;
+    static int         socket;
+    sync_string                sync_signal;
+    char               transaction_string[MAX_STR1_LEN];
+    char               buf[128];
+
+    if ((int)strlen(data) > MAX_STR2_LEN) {
+       (void) fprintf(stderr,
+                       "%s: %s too much data len = %d max = %d\n",
+                       sfs_Myname, Prime_client, strlen(data),
+                       MAX_STR2_LEN);
+       return((int)RPC_CANTENCODEARGS);
+    }
+
+    if (clnt_handle == NULL) {
+       struct sockaddr_in      prime_addr;
+       struct hostent *        host_info;
+
+       socket = RPC_ANYSOCK;
+
+       /* get host information for prime_client */
+       if ((host_info = gethostbyname(Prime_client)) == NULL) {
+           (void) fprintf(stderr, "%s: %s is unknown host\n",
+                       sfs_Myname, Prime_client);
+           return ((int) RPC_UNKNOWNHOST);
+       }
+
+       (void) memset((char *) &prime_addr, '\0', sizeof(prime_addr));
+       (void) memmove((char *) &prime_addr.sin_addr,
+                       (char *) host_info->h_addr, host_info->h_length);
+
+       prime_addr.sin_family = AF_INET;
+       prime_addr.sin_port =  0;
+
+       /*
+        * Create client "handle" used for calling SFS_SYNCPROG on the
+        * Prime Client. We tell the RPC package to use the "tcp"
+        * protocol when contacting the prime_client.
+        */
+       clnt_handle = clnttcp_create(&prime_addr, SFS_SYNCPROG,
+                       SFS_SYNCVERS, &socket, MAX_STR2_LEN, MAX_STR2_LEN);
+
+       if (clnt_handle == ((CLIENT *) NULL)) {
+           /*
+            * Couldn't establish connection with the Prime_Client.
+            * Print error message and return error.
+            */
+           clnt_pcreateerror(Prime_client);
+           (void) fprintf(stderr,
+               "%s: %s Could not establish client handle to contact %s\n",
+               lad_timestamp(), sfs_Myname, Prime_client);
+           return((int) RPC_FAILED);
+       }
+    }
+
+    /* fill up xdr structure with data to send to Prime Client */
+    (void) sprintf(transaction_string,"%d_%i", Client_num, ++transaction_id);
+    sync_signal.clnt_type = type;
+    sync_signal.clnt_id = Client_num;
+    sync_signal.clnt_data = data;
+    sync_signal.clnt_transaction = transaction_string;
+
+    /* Call the remote procedure "signal_sfs_1" on the Prime Client */
+    result = signal_sfs_1(&sync_signal, clnt_handle);
+    if (result == NULL) {
+       /*
+        * An error occurred while making RPC to the Prime Client.
+        * Print error message and return error.
+        */
+       sprintf(buf, "%s Transaction %s: Could not call prime client %s",
+                       lad_timestamp(), transaction_string, Prime_client);
+       clnt_perror(clnt_handle, buf);
+       return((int) RPC_CANTSEND);
+    }
+
+    /* OK, we successfully called the remote procedure. */
+    if (*result == 0) {
+       /*
+        * remote procedure was unable to successfully perform required
+        * operation on the Prime Client.
+        * Print error message and return error.
+        */
+       (void) fprintf(stderr,
+                       "%s: %s Prime Client couldn't write to PC_sync file \n",
+                       sfs_Myname, Prime_client);
+       return((int) RPC_FAILED);
+    }
+
+    /* remote procedure success - wrote to Prime Client sync file */
+    return((int) RPC_SUCCESS);
+
+} /* signal_Prime_Client */
+
+
+/*
+ * Read results arrays for 'children' children from Logfile
+ * and accumulate them in "Ops".
+ * Complain about any problems we see with the log file.
+ */
+static void
+collect_counters(
+    int                        children)
+{
+    int                                i;
+    int                                j;
+    struct stat                        statb;
+    sfs_results_report_type    report; /* final results log */
+    int                                Saveerrno;
+
+    if (fstat(Log_fd, &statb) == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't stat log %s ", sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror(Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(79);
+    }
+
+    if (statb.st_size != (children * sizeof(report))) {
+       (void) fprintf(stderr, "%s: log file %s has bad format\n",
+                       sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(80);
+    }
+
+    if (lseek(Log_fd, 0L, 0) == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't lseek log %s ", sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror("lseek");
+       (void) generic_kill(0, SIGINT);
+       exit(81);
+    }
+
+    for (j = 0; j < NOPS + 1; j++) {
+       Ops[j].results.good_calls = 0;
+       Ops[j].results.bad_calls = 0;
+       Ops[j].results.fast_calls = 0;
+       Ops[j].results.time.sec = 0;
+       Ops[j].results.time.usec = 0;
+       Ops[j].results.msec2 = 0;
+    }
+    Total_fss_bytes = 0;
+    Least_fss_bytes = 0;
+    Most_fss_bytes = 0;
+    Base_fss_bytes = 0;
+
+    for (i = 0; i < children; i++) {
+       if (read(Log_fd, (char *) &report, sizeof(report)) == -1) {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "%s: can't read log %s", sfs_Myname, Logname);
+           errno = Saveerrno;
+           perror("Logname");
+           (void) generic_kill(0, SIGINT);
+           exit(82);
+       }
+
+       for (j = 0; j < NOPS + 1; j++) {
+           Ops[j].results.good_calls += report.results_buf[j].good_calls;
+           Ops[j].results.bad_calls += report.results_buf[j].bad_calls;
+           Ops[j].results.fast_calls += report.results_buf[j].fast_calls;
+           ADDTIME(Ops[j].results.time, report.results_buf[j].time);
+           Ops[j].results.msec2 += report.results_buf[j].msec2;
+       }
+       Total_fss_bytes += report.total_fss_bytes;
+       Least_fss_bytes += report.least_fss_bytes;
+       Most_fss_bytes += report.most_fss_bytes;
+       Base_fss_bytes += report.base_fss_bytes;
+    }
+
+} /* collect_counters */
+
+
+/*
+ * Check the parameters for validity.
+ */
+static int
+check_parameters(
+char * iodist_file,
+char * mix_file,
+int    runtime_val)
+{
+    int retval = 0;
+    char detail[40];
+
+    detail[0] = '\0';
+
+    if (iodist_file != NULL) {
+       retval = INVALID_IODIST;
+    }
+    if (mix_file != NULL) {
+       retval = INVALID_MIX;
+    }
+    if (runtime_val != DEFAULT_RUNTIME) {
+       (void) sprintf(detail, "%d != %d", runtime_val, DEFAULT_RUNTIME);
+       retval = INVALID_RUNTIME;
+    }
+    if (Access_percent != DEFAULT_ACCESS) {
+       (void) sprintf(detail, "%d != %d", Access_percent, DEFAULT_ACCESS);
+       retval = INVALID_ACCESS;
+    }
+    if (Append_percent != DEFAULT_APPEND) {
+       (void) sprintf(detail, "%d != %d", Append_percent, DEFAULT_APPEND);
+       retval = INVALID_APPEND;
+    }
+    if (Kb_per_block != DEFAULT_KB_PER_BLOCK) {
+       (void) sprintf(detail, "%d != %d", Kb_per_block, DEFAULT_KB_PER_BLOCK);
+       retval = INVALID_KB;
+    }
+    if (Files_per_dir != DEFAULT_FILES_PER_DIR) {
+       (void) sprintf(detail, "%d != %d", Files_per_dir, DEFAULT_FILES_PER_DIR);
+       retval = INVALID_NDIRS;
+    }
+    if (Fss_delta_percent != DEFAULT_DELTA_FSS) {
+       (void) sprintf(detail, "%d != %d",
+                               Fss_delta_percent, DEFAULT_DELTA_FSS);
+       retval = INVALID_FSS;
+    }
+    if (Biod_max_outstanding_reads < DEFAULT_BIOD_MAX_READ) {
+       (void) sprintf(detail, "%d < %d",
+                       Biod_max_outstanding_reads, DEFAULT_BIOD_MAX_READ);
+       retval = INVALID_BIODREAD;
+    }
+    if (Tot_client_num_symlinks != DEFAULT_NSYMLINKS) {
+       (void) sprintf(detail, "%d != %d",
+                       Tot_client_num_symlinks, DEFAULT_NSYMLINKS);
+       retval = INVALID_NSYMLINKS;
+    }
+    if (Biod_max_outstanding_writes < DEFAULT_BIOD_MAX_WRITE) {
+       (void) sprintf(detail, "%d < %d",
+                       Biod_max_outstanding_writes, DEFAULT_BIOD_MAX_WRITE);
+       retval = INVALID_BIODWRITE;
+    }
+    if (Warmuptime != DEFAULT_WARMUP) {
+       (void) sprintf(detail, "%d != %d",
+                       Warmuptime, DEFAULT_WARMUP);
+       retval = INVALID_WARMUP;
+    }
+
+    if (retval != 0)
+       (void) fprintf(stdout,
+               "%s: INVALID RUN, ILLEGAL PARAMETER: Non-standard %s %s\n",
+               sfs_Myname, invalid_str[retval], detail);
+    return (retval);
+}
+
+/*
+ * Check the results in Ops[] for validity.
+ */
+static int
+check_counters(void)
+{
+    double     mix_pcnt;
+    int                bad_pcnt;
+    int                i;
+    int                ret = 0;
+
+    if (Ops[TOTAL].results.good_calls <= 0) {
+       (void) fprintf(stdout, "%s: INVALID RUN %s\n",
+                               sfs_Myname, invalid_str[INVALID_GOODCALLS]);
+       ret = INVALID_GOODCALLS;
+    }
+    if (Ops[TOTAL].results.good_calls != 0)
+        bad_pcnt = (Ops[TOTAL].results.bad_calls * 100)
+              / Ops[TOTAL].results.good_calls;
+    else
+       bad_pcnt = 100;
+
+    if (bad_pcnt >= 1) {
+       (void) fprintf(stdout, "%s: INVALID RUN, %d%% %s\n",
+
+                       sfs_Myname, bad_pcnt,
+                       invalid_str[INVALID_FAILEDRPC]);
+       ret = INVALID_FAILEDRPC;
+    }
+
+    if (Ops[TOTAL].results.good_calls == 0) {
+       (void) fprintf(stdout, "%s: INVALID RUN, no good calls\n", sfs_Myname);
+       return (INVALID_NOTMIX);
+    }
+
+    for (i = 0; i < NOPS; i++) {
+       mix_pcnt = ((double)Ops[i].results.good_calls /
+                                       Ops[TOTAL].results.good_calls) * 100.0;
+       if (mix_pcnt != (double)Ops[i].mix_pcnt) {
+           if ((mix_pcnt - (double)Ops[i].mix_pcnt > 1.5) ||
+               ((double)Ops[i].mix_pcnt - mix_pcnt > 1.5)) {
+               (void) fprintf(stdout, "%s: INVALID RUN, %s target %d%% actual %4.1f%% %s\n",
+
+                       sfs_Myname, Ops[i].name, Ops[i].mix_pcnt, mix_pcnt,
+                       invalid_str[INVALID_NOTMIX]);
+               ret = INVALID_NOTMIX;
+           }
+       }
+    }
+
+    return (ret);
+
+} /* check_counters */
+
+
+/*
+ * Print the test run results, for 'load' load, the operation percentages
+ * in 'mixfile' percentages, and 'children' processes.
+ */
+static void
+print_results(
+    int                                children,
+    int                                load,
+    char *                     mix_file,
+    int                                invalid_flag,
+    int                                runtime_val,
+    char *                     iodist_file)
+{
+    uint_t                     runtime;
+    uint_t                     total_msec;
+    uint_t                     msec;
+    uint_t                     total_calls;
+    uint_t                     calls;
+    int                                i;
+    double                     squared_time_msec;
+    double                     sum2_msec;
+    double                     var_msec;
+    double                     stdev_msec;
+    double                     sq_conf_interval_msec;
+    double                     conf_interval_msec;
+    sfs_op_type *              op_ptr;
+    sfs_results_type *         results_ptr;
+    char                       result_string[MAX_LINE_LEN];
+
+
+    /* compute total time for all ops combined */
+    total_msec = 0;
+    for (i = 0; i < NOPS; i++) {
+       total_msec += Ops[i].results.time.sec * 1000;
+       total_msec += Ops[i].results.time.usec / 1000;
+    }
+
+    /*
+     * Report statistics based on successful calls only.  The per
+     * operation routines accumulate time and count only good_calls.
+     */
+    total_calls = Ops[TOTAL].results.good_calls;
+
+
+    /*
+     * Print the client's test parameters
+     */
+    (void) fprintf(stderr, "\n\nClient Test Parameters: \n");
+    (void) fprintf(stderr, "\tNumber of processes = %d\n", children);
+    (void) fprintf(stderr, "\tRequested Load (NFS V%d operations/second) = %d\n",
+                   nfs_version, load);
+    (void) fprintf(stderr, "\tMaximum number of outstanding biod writes = %d\n",
+                   Biod_max_outstanding_writes);
+    (void) fprintf(stderr, "\tMaximum number of outstanding biod reads = %d\n",
+                   Biod_max_outstanding_reads);
+    (void) fprintf(stderr, "\tWarm-up time (seconds) = %d\n\tRun time (seconds) = %d\n",
+                   Warmuptime, runtime_val);
+    if (mix_file)
+       (void) fprintf(stderr,"\tNFS Mixfile = %s\n", mix_file);
+    if (iodist_file)
+       (void) fprintf(stderr,"\tBlock Size Distribution file = %s\n",
+                       iodist_file);
+    (void) fprintf(stderr, "\tFile Set = %4d Files created for I/O operations\n",
+               (Tot_client_num_io_files/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Files accessed for I/O operations\n",
+               (((Tot_client_num_io_files/children + 1) * Access_percent)
+                  / 100) * children);
+    (void) fprintf(stderr, "\t\t   %4d Files for non-I/O operations\n",
+               (Tot_client_num_non_io_files/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Symlinks\n",
+               (Tot_client_num_symlinks/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Directories\n",
+               ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
+    (void) fprintf(stderr, "\t\t\tAdditional non-I/O files created as necessary\n\n");
+
+    (void) sprintf(Client_results,"%d %d %d %d %d %d\n",
+       nfs_version,
+       (Tot_client_num_io_files/children + 1) * children,
+       (((Tot_client_num_io_files/children + 1) * Access_percent)
+               / 100) *children,
+       (Tot_client_num_non_io_files/children + 1) * children,
+       (Tot_client_num_symlinks/children + 1) * children,
+       ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
+
+    /* print the client's results header information */
+    (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
+                                SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fprintf(stdout, "SFS Single Client (%s) Results, %s\n",
+                   lad_hostname, lad_timestamp());
+    (void) fflush(stdout);
+
+    /* print column headers for per operation statistics */
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n");
+    (void) fprintf(stdout, "\n");
+    (void) fprintf(stdout,
+"NFS V%d     Target Actual   NFS    NFS    Mean     Std Dev  Std Error   Pcnt \n",
+nfs_version);
+    (void) fprintf(stdout,
+"Op           NFS    NFS     Op     Op    Response Response of Mean,95%%  of  \n");
+    (void) fprintf(stdout,
+"Type         Mix    Mix   Success Error   Time     Time    Confidence  Total\n");
+    (void) fprintf(stdout,
+"             Pcnt   Pcnt   Count  Count  Msec/Op  Msec/Op  +- Msec/Op  Time \n");
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n");
+    (void) fflush(stdout);
+
+    /* print per operation statistics */
+    for (i = 0; i < NOPS; i++) {
+       /* init to 0 */
+       squared_time_msec = 0.0;
+       sum2_msec = 0.0;
+       calls = 0;
+       msec = 0;
+       stdev_msec = 0;
+
+       op_ptr = &Ops[i];
+       results_ptr = &op_ptr->results;
+
+       /* get the number successful calls and total time */
+       calls = op_ptr->results.good_calls;
+       msec = (results_ptr->time.sec * 1000)
+              + (results_ptr->time.usec / 1000);
+
+       /* compute the standard deviation for the mean response time */
+       if (calls <= 1)
+           stdev_msec = 0;
+       else {
+           /* get the standard deviation */
+           squared_time_msec = results_ptr->msec2;
+           /* compute the square of the total elapsed time */
+           sum2_msec = (results_ptr->time.sec * 1000.0)
+                        + (results_ptr->time.usec / 1000.0);
+           sum2_msec *= sum2_msec;
+
+           /* variance = 1/(n-1) * (sum(x^2) - 1/n * (sum(x))^2) */
+           var_msec = (squared_time_msec - (sum2_msec / calls)) / (calls-1);
+           if (var_msec == 0.0) {
+               stdev_msec = 0.0;
+           } else
+               stdev_msec = sqrt(var_msec);
+       }
+
+       /* compute the confidence interval */
+       if (calls != 0) {
+           sq_conf_interval_msec = DEFAULT_CHI_SQR_CI * (stdev_msec / calls);
+           if (sq_conf_interval_msec == 0.0) {
+               conf_interval_msec = 0.0;
+           } else
+               conf_interval_msec = sqrt(sq_conf_interval_msec);
+       } else
+           conf_interval_msec = 0.0;
+
+       /* print the per op statistics */
+       (void) fprintf(stdout,
+       "%-12s%3d%%   %4.1f%%   %5d %5d %5.2f %8.2f  %8.2f    %3.1f%%\n",
+           op_ptr->name,                                       /* op name */
+           op_ptr->mix_pcnt,                                   /* target mix */
+                                                               /* actual mix */
+           total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
+           results_ptr->good_calls,                            /* successes */
+           results_ptr->bad_calls,                             /* errors */
+           calls ? ((double)msec / calls) : 0.0,               /* msec/call */
+           stdev_msec,                                         /* std dev */
+           conf_interval_msec,                                 /* conf int */
+                                                               /* % of time */
+           total_msec ? ((double)msec / total_msec) * 100 : 0.0);
+       (void) fflush(stdout);
+
+       /*
+        * Store client data in result_string.
+        * This string is different from client result display.
+        * The  squared_time_msec and sum2_msec values are passed along
+        * to be used by the prime client to calculate the stddev value for
+        * each operation.
+        */
+       if (Prime_client) {
+       (void) sprintf(result_string,
+       "%-12s   %3d%% %3.1f%% %5d  %5d %4ld.%1ld %6.2f  %3.1f%% %f %f\n",
+           op_ptr->name,                                       /* op name */
+           op_ptr->mix_pcnt,                                   /* target mix */
+                                                               /* actual mix */
+           total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
+           results_ptr->good_calls,                            /* successes */
+           results_ptr->bad_calls,                             /* errors */
+           results_ptr->time.sec,                              /* total time1*/
+           results_ptr->time.usec / 100000,                    /* total time2*/
+           calls ? ((double)msec / calls) : 0.0,               /* msec/call */
+                                                               /* % of time */
+           total_msec ? ((double)msec / total_msec) * 100 : 0.0,
+           squared_time_msec,                                  /* sum of sqs */
+           sum2_msec);                                         /* sq of sums */
+           (void) strcat(Client_results, result_string);
+       }
+
+    } /* end for each op */
+
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n\n");
+    (void) fflush(stdout);
+
+    /* Average child runtime.  (should this be the longest runtime?) */
+    runtime = Ops[TOTAL].results.time.sec / children;
+
+    /* Print summary */
+    (void) fprintf(stdout,
+       "      ------------------------------------------------------------\n");
+    (void) fprintf(stdout,
+       "      | SPEC SFS VERSION %6s SINGLE CLIENT RESULTS SUMMARY    |\n",
+                                                       SFS_VERSION_NUM);
+    (void) fprintf(stdout,
+       "      ------------------------------------------------------------\n");
+    (void) fprintf(stdout, "NFS V%d THROUGHPUT: ", nfs_version);
+    (void) fprintf(stdout,
+                   "%4d.%02d Ops/Sec   AVG. RESPONSE TIME: %4d.%02d Msec/Op\n",
+                   runtime ? (total_calls / runtime) : 0,
+                   runtime ? ((total_calls % runtime) * 100 / runtime) : 0,
+                   total_calls ? (total_msec / total_calls) : 0,
+                   total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0);
+    (void) fprintf(stdout, "%s PROTOCOL\n", Tcp ? "TCP" : "UDP");
+    (void) fprintf(stdout, "FAST CALLS: %d\n", Ops[TOTAL].results.fast_calls);
+    (void) fprintf(stdout, "NFS MIXFILE: ");
+    if (mix_file)
+       (void) fprintf(stdout,"%s\n", mix_file);
+    else
+       (void) fprintf(stdout,"[ SFS Default ]\n");
+    (void) fprintf(stdout, "CLIENT REQUESTED LOAD: %d Ops/Sec \n", load);
+    (void) fprintf(stdout,
+                       "TOTAL NFS OPERATIONS: %-6d      TEST TIME: %d Sec \n",
+                       total_calls, runtime);
+    (void) fprintf(stdout, "FILE SET SIZE CREATED: %d KB\n",
+                                                       Total_fss_bytes);
+    (void) fprintf(stdout,
+               "FILE SET SIZE ACCESSED: %d - %d KB  (%d%% to %d%% of Base)\n",
+               Least_fss_bytes, Most_fss_bytes,
+               (100 * Least_fss_bytes) / Base_fss_bytes,
+               (100 * Most_fss_bytes) / Base_fss_bytes);
+    (void) fprintf(stdout, "\n");
+    (void) fprintf(stdout,
+    "------------------------------------------------------------------------");
+    (void) fprintf(stdout, "\n\n");
+    (void) fflush(stdout);
+
+    /*
+     * store client summary results and Invalid run indicator
+     * to send to the Prime_client
+     */
+    if (Prime_client) {
+       (void) sprintf(result_string,"%d.%02d %d.%02d %d %d %d %d %d %d %d\n",
+           runtime ? (total_calls / runtime) : 0,          /* ops/sec1 */
+           runtime ? ((total_calls % runtime) * 100 / runtime) : 0, /* ops/sec2 */
+           total_calls ? (total_msec / total_calls) : 0,       /* mean1 */
+           total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0, /* mean2 */
+           runtime,                                        /* run time */
+           total_calls,                                    /* # ops */
+           invalid_flag,                                   /* valid flag */
+           Total_fss_bytes,                                /* total fileset */
+           Least_fss_bytes,                                /* fileset low */
+           Most_fss_bytes,                                 /* fileset high */
+           Base_fss_bytes);                                /* fileset base */
+       (void) strcat(Client_results, result_string);
+    }
+
+} /* print_results */
+
+
+/* ARGSUSED */
+static void
+sfs_reaper(
+    int                sig_id)
+{
+    (void) fprintf(stderr, "%s: caught unexpected SIGCHLD. Exiting...\n",
+                      sfs_Myname);
+    /* cleanup and exit */
+    (void) signal_Prime_Client("CLIENT_STOP", "");
+    (void) generic_kill(0, SIGINT);
+    exit(83);
+}
+/* sfs_c_pnt.c */
diff --git a/TBBT/trace_play/sfs_c_rnd.c b/TBBT/trace_play/sfs_c_rnd.c
new file mode 100644 (file)
index 0000000..b3a0174
--- /dev/null
@@ -0,0 +1,247 @@
+#ifndef lint
+static char sfs_c_rndSid[] = "@(#)sfs_c_rnd.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_rnd.c ---------------------
+ *
+ *      Random number generator.
+ *
+ *.Exported_routines
+ *     int32_t sfs_random(void)
+ *     void sfs_srandom(int)
+ *
+ *.Local_routines
+ *     double ran(void)
+ *     int32_t spec_rand(void)
+ *     void spec_srand(int)
+ *
+ *.Revision_History
+ *     28-Nov-91       Teelucksingh    ANSI C
+ *     01-Aug-91       Wiryaman        sfs_srandom() and sfs_random()
+ *                                     now use spec_srand() and spec_rand()
+ *                                     instead of srandom() and random().
+ *      17-Apr-91       Wittle         Created.
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+/*
+ * Here's the source for the random number generator that SPEC uses.
+ * The function to be called is "spec_rand" which returns an integer
+ * between 1 and MAX_INT-1.
+ *
+ * One question we may wanna think about is the seeding of the random
+ * number generator. Do we start with the same seed everytime (for
+ * repeatability) or use a array of possible seeds (some seeds are better
+ * than others and SPEC prople mention that they have a list of 15
+ * "good" seeds).
+ */
+
+
+/*
+ * -------------------------  Static Declarations  -------------------------
+ */
+
+static int32_t seedi = 2231;
+
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+static double ran(void);
+static int32_t spec_rand(void);
+static void spec_srand(int);
+
+/*
+ * -----------------------  Random Number Routines  -----------------------
+ */
+
+
+/*
+ * Seed the random number generator.
+ */
+static void
+spec_srand(
+    int seed)
+{
+    seedi = seed;
+}
+
+
+/*
+ * Returns a random number.
+ */
+static int32_t
+spec_rand(void)
+{
+    (void) ran();
+    return(seedi);
+}
+
+
+/*
+ * Compute the next random number.
+ */
+static double
+ran(void)
+
+/* See "Random Number Generators: Good Ones Are Hard To Find", */
+/*     Park & Miller, CACM 31#10 October 1988 pages 1192-1201. */
+/***********************************************************/
+/* THIS IMPLEMENTATION REQUIRES AT LEAST 32 BIT INTEGERS ! */
+/***********************************************************/
+
+#define _A_MULTIPLIER  16807L
+#define _M_MODULUS     2147483647L /* (2**31)-1 */
+#define _Q_QUOTIENT    127773L     /* 2147483647 / 16807 */
+#define _R_REMAINDER   2836L       /* 2147483647 % 16807 */
+{
+    int32_t    lo;
+    int32_t    hi;
+    int32_t    test;
+
+    hi = seedi / _Q_QUOTIENT;
+    lo = seedi % _Q_QUOTIENT;
+    test = _A_MULTIPLIER * lo - _R_REMAINDER * hi;
+    if (test > 0) {
+       seedi = test;
+    } else {
+       seedi = test + _M_MODULUS;
+    }
+    return((float) seedi / _M_MODULUS);
+}
+
+/*
+ * Local interface to seed random number generator.
+ */
+void
+sfs_srandom(
+    int                seed)
+{
+    spec_srand(seed);
+}
+
+
+/*
+ * Local interface to obtain a random number.
+ */
+int32_t
+sfs_random(void)
+{
+    return(spec_rand());
+}
+
+static struct r_array {
+       int n1;
+       int n2;
+} *r_array;
+
+static int r_length = 0;
+
+static int
+r_array_compare(const void *i, const void *j)
+{
+       if (((struct r_array *)i)->n2 > ((struct r_array *)j)->n2)
+               return (1);
+       if (((struct r_array *)i)->n2 < ((struct r_array *)j)->n2)
+               return (-1);
+       return (0);
+}
+
+int
+init_rand_range(int length)
+{
+       int i;
+
+       /*
+        * If array already exists free it
+        */
+       if (r_length != 0) {
+               (void)free(r_array);
+               r_length = 0;
+       }
+
+       /*
+        * If length is zero just free memory and return
+        */
+       if (length == 0)
+               return (0);
+
+       /*
+        * Allocate array of sequential numbers and random numbers
+        */
+       if ((r_array = malloc(length * sizeof(struct r_array))) == NULL)
+               return (1);
+
+       r_length = length;
+
+       /*
+        * Initialize array of sequential values and random values
+        */
+       for (i = 0; i < length; i++) {
+               r_array[i].n1 = i;
+               r_array[i].n2 = sfs_random();
+       }
+
+       /*
+        * Sort random array values to put sequential values in random order
+        */
+       qsort(r_array, length, sizeof(struct r_array), r_array_compare);
+
+       return (0);
+}
+
+int
+rand_range(int index)
+{
+       return (r_array[index].n1);
+}
+/* sfs_c_rnd.c */
diff --git a/TBBT/trace_play/sfs_c_sig.c b/TBBT/trace_play/sfs_c_sig.c
new file mode 100644 (file)
index 0000000..7826377
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef lint
+static char sfs_c_sigSid[] = "@(#)sfs_c_sig.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_sig.c ---------------------
+ *
+ *      Signal handling.  Routines to send and catch signals.
+ *
+ *.Exported_Routines
+ *     void sfs_alarm(int)
+ *     void sfs_startup(int)
+ *     void sfs_stop(int)
+ *     void sfs_cleanup(int)
+ *
+ *.Local_Routines
+ *     None.
+ *
+ *.Revision_History
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <sys/signal.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+#ifndef RFS
+/*
+ * -------------------------  Signal Handlers  -------------------------
+ */
+
+void
+sfs_alarm(
+    int         sig_id)
+{
+#if !(defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    (void) signal(sig_id, sfs_alarm);
+#endif
+    if (DEBUG_CHILD_SIGNAL)
+       (void) fprintf(stderr, "%s: caught Signal %d\n", sfs_Myname, sig_id);
+    (void) fflush(stderr);
+
+} /* sfs_alarm */
+
+
+/*
+ * Signal Handler
+ * Catch the parent's "start" signal.
+ */
+void
+sfs_startup(
+    int        sig_id)
+{
+#if !(defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    (void) signal(SIGUSR1, sfs_startup);
+#endif
+    if (DEBUG_CHILD_SIGNAL)
+       (void) fprintf(stderr, "%s: caught Signal %d SIGUSR1\n",
+                      sfs_Myname, sig_id);
+
+    if (Child_num == -1)
+       /* I'm the parent, ignore the signal */
+       return;
+
+    /*
+     * SIGUSR1 is used to make all phase transitions, but we
+     * only want to make the Warmup -> Testrun switch here
+     */
+    if (Current_test_phase != Warmup_phase)
+       return;
+
+    Current_test_phase = Testrun_phase;
+    start_run_phase++;
+} /* sfs_startup */
+
+
+/*
+ * Signal Handler
+ * Catch the parent's "stop" signal.
+ */
+void
+sfs_stop(
+    int                sig_id)
+{
+#if !(defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    (void) signal(SIGUSR2, sfs_stop);
+#endif
+    if (DEBUG_CHILD_SIGNAL)
+       (void) fprintf(stderr, "%s: caught Signal %d SIGUSR2\n",
+                      sfs_Myname, sig_id);
+
+    /* end the test */
+    Runtime = 0;
+    Current_test_phase = Results_phase;
+
+} /* sfs_stop */
+
+#endif
+
+
+/*
+ * SIGINT, SIGTERM handler
+ * Clean up and exit due to an error/abort condition.
+ * We assume if NFS_client was valid, then MOUNT_client was also valid.
+ */
+void
+sfs_cleanup(
+    int                sig_id)
+{
+    if (DEBUG_CHILD_SIGNAL)
+       (void) fprintf(stderr, "%s: caught Signal %d SIGINT\n",
+                      sfs_Myname, sig_id);
+
+    (void) unlink(Logname);
+    if (NFS_client != ((CLIENT *) NULL))
+       clnt_destroy(NFS_client);
+    exit(65);
+
+} /* sfs_cleanup */
+
+/* sfs_c_sig.c */
diff --git a/TBBT/trace_play/sfs_c_sub.c b/TBBT/trace_play/sfs_c_sub.c
new file mode 100644 (file)
index 0000000..7f91b89
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef lint
+static char sfs_c_subSid[] = "@(#)sfs_c_sub.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_sub.c ---------------------
+ *
+ *      Subroutines common to both sfs and sfs_prime_client.
+ *
+ *.Exported_Routines
+ *     int generic_kill(int, int)
+ *     void generic_catcher(int)
+ *     char * lad_timestamp(void)
+ *
+ *.Local_Routines
+ *     None.
+ *
+ *.Revision_History
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/signal.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+/*
+ * Common data shared between sfs and sfs_prime
+ *
+ * Values for invalid runs
+ */
+char *invalid_str[INVALID_MAX] = {
+       "No error",
+       "Unknown",
+       "IO distribution file",
+       "Mix file",
+       "Runtime",
+       "Access percentage",
+       "Append percentage",
+       "KB per block",
+       "Number client directories",
+       "Fileset delta",
+       "Max biod reads",
+       "Number symlinks",
+       "Max biod writes",
+       "Warmup time",
+       "No good calls",
+       "Failed RPC calls",
+       "Op mix missed",
+};
+
+/*
+ * -------------------------  Signal Handlers  -------------------------
+ */
+
+/*
+ * Signal Sender.  Send signal 'sig' to process 'pid'.
+ */
+int
+generic_kill(
+    int        pid,
+    int        signal)
+{
+    if (DEBUG_PARENT_SIGNAL)
+       (void) fprintf(stderr,
+                       "%s: sending Pid %d Signal %d\n", sfs_Myname, pid ,signal);
+    return(kill((pid_t)pid, signal));
+
+} /* generic_kill */
+
+
+/*
+ * Signal Handler.  Catch and reset the handler for signal 'i'.
+ */
+void
+generic_catcher(
+    int        i)
+{
+#if !(defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    (void) signal(i, generic_catcher);
+#endif
+    if (DEBUG_CHILD_SIGNAL)
+       (void) fprintf(stderr, "%s: caught Signal %d\n", sfs_Myname, i);
+    (void) fflush(stderr);
+
+} /* generic_catcher */
+
+
+
+/*
+ * get the date and time and return a string, remove the END-OF-LINE (\n)
+ */
+char *
+lad_timestamp(void)
+{
+    static time_t      run_date;
+    static char                date_string[26];
+
+    run_date = time((time_t *)NULL);
+    (void) strncpy((char *) date_string, (char *) ctime(&run_date), 24);
+    return(date_string);
+
+} /* lad_timestamp */
+
+int
+set_debug_level(char *s)
+{
+    unsigned int i;
+    unsigned int first;
+    unsigned int last;
+    unsigned int level = 0;
+
+    if (s == NULL || *s == '\0')
+       return(0);
+
+    for (;;) {
+       if (*s == ',') {
+           s++;
+           continue;
+       }
+
+       /* find first flag to set */
+       i = 0;
+       while (isdigit(*s))
+           i = i * 10 + (*s++ - '0');
+       first = i;
+
+       /* find last flag to set */
+       if (*s == '-') {
+           i = 0;
+           while (isdigit(*++s))
+               i = i * 10 + (*s - '0');
+       }
+       last = i;
+
+       if (first != 0 && last != 0 && first < 32 && last < 32) {
+           for (i = first - 1; i < last; i++) {
+               level |= (1 << i);
+           }
+       }
+
+       /* more arguments? */
+       if (*s++ == '\0')
+               return (level);
+    }
+}
+
+/* sfs_c_sub.c */
diff --git a/TBBT/trace_play/sfs_ext_mon b/TBBT/trace_play/sfs_ext_mon
new file mode 100755 (executable)
index 0000000..841e9a1
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+#      @(#)sfs_ext_mon 2.1     97/10/23
+#
+# This sample shell script can be used to start and stop
+# external processes at the beginning and ending of the
+# sfs load generation period respectively. The name of
+# this program is pased in via the PRIME_MON_SCRIPT variable
+# in the sfs_rc or equivalent file. The sfs_prime program
+# executes this shell script just before it issues the START
+# message to all the clients ie. "script_name START"; and likewise
+# another call after all the clients have completed load generation ie.
+# "script_name DONE".
+#
+# All environment variables exported from sfs_mgr are available for use.
+#
+EXT_MON_ARG=""
+if [ $# -gt 1 ]
+then
+    EXT_MON_ARG="$2"
+fi
+
+#
+#----------------- START section -----------------
+# Code section that handles starting of external processes.
+# ALL PROCESSES SHOULD BE STARTED IN THE BACKGROUND OR ELSE
+# THE TEST WILL BLOCK WAITING FOR THEIR COMPLETION!!
+#
+if [ "$1" = "START" ]; then
+       #
+       # place commands to start performance monitoring utilities as
+       # background processes here.
+       #
+       echo "$0: started external monitoring utilities" >&2
+       exit 0
+fi
+
+#
+#----------------- DONE section -----------------
+# Code section that handles stopping of external processes.
+# ALL PROCESSES SHOULD BE STARTED IN THE BACKGROUND OR ELSE
+# THE TEST WILL BLOCK WAITING FOR THEIR COMPLETION!!
+#
+if [ "$1" = "DONE" ]; then
+       #
+       # place commands to stop performance monitoring utilities as
+       # background processes here.
+       #
+       echo "$0: stopped external monitoring utilities" >&2
+       exit 0
+fi
+
+#
+#----------------- ERROR section -----------------
+# ERROR: BAD PARAMETER
+#
+echo "$0: bad param. " >&2
+echo "usage: $0 START | DONE " >&2
+exit 1
diff --git a/TBBT/trace_play/sfs_m_def.h b/TBBT/trace_play/sfs_m_def.h
new file mode 100644 (file)
index 0000000..bd01ec6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * @(#)sfs_m_def.h     2.1     97/10/23
+ */
+
+/*
+ *     Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+#define MAX_LINE_LEN 160               /* max per line results string */
+#define MAX_STR1_LEN 31                /* max msg, number, and xid str len */
+#define MAX_STR2_LEN 2560              /* total results data string length */
+#define MULTICLIENT_OFFSET 500         /* Runtime offset */
+
+/* multi-client sync logfiles and prefixes */
+#define SFS_CLIENT_SYNC_LOG "/tmp/sfs_CL" /* client logfile prefix */
+#define SFS_PRIME_SYNC_LOG "/tmp/sfs_PC_sync" /* prime client logfile */
+#define PRIME_RESULTS_LOG "/tmp/sfs_res"  /* prime results logfile prefix */
+
+struct sync_string {
+       int clnt_id;                            /* client number */
+       char *clnt_type;                        /* message type, hard coded */
+       char *clnt_transaction;                 /* transaction id */
+       char *clnt_data;                        /* results strings */
+};
+typedef struct sync_string sync_string;
+
+#define SFS_SYNCPROG ((uint32_t) 100500)
+#define SFS_SYNCVERS ((uint32_t) 1)
+#define SIGNAL_NULLPROC ((uint32_t) 0)
+#define SIGNAL_SFS ((uint32_t) 1)
+
+extern bool_t  xdr_sync_string(XDR *, sync_string *);
+extern int *    signal_sfs_1(sync_string *, CLIENT *);
diff --git a/TBBT/trace_play/sfs_m_msg.c b/TBBT/trace_play/sfs_m_msg.c
new file mode 100644 (file)
index 0000000..80fbeec
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef lint
+static char sfs_m_msgSid[] = "@(#)sfs_m_msg.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *.Exported_routines
+ *     int * signal_sfs_1(sync_string *, CLIENT *);
+ *
+ *.Local_routines
+ *     None.
+ *
+ *.Revision_history
+ *     04-Dec-91       Keith           Include sfs_def.h for SYSV/SVR4
+ *                                     mem* routines.
+ *     17-Jun-91       Teelucksingh    Create multi-client synchronization
+ *                                     rpc definition
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+/*
+ * -----------------------  Static Definitions  -----------------------
+ */
+
+/*
+ * Almost all rpcs are sent over TCP so we have a reliable transport,
+ * unfortunately the initialization phase may highly overload the
+ * server and the previous default of 5 seconds might timeout before
+ * it gets acknowledged.  The risk of a large timeout is that there is
+ * an added period after a stop message is sent.  This is usually not
+ * a problem.
+ */
+static struct timeval TIMEOUT = { 60, 0 };
+
+
+/*
+ * -------------------  Multi-client Message Handling  -------------------
+ */
+
+int *
+signal_sfs_1(
+    sync_string *      argp,
+    CLIENT *           clnt)
+{
+    static int         res;
+
+    (void) memset((char *) &res, '\0', sizeof(res));
+    if (clnt_call(clnt, SIGNAL_SFS, xdr_sync_string, (caddr_t)argp, xdr_int,
+                 (caddr_t)&res, TIMEOUT) != RPC_SUCCESS) {
+       return (NULL);
+    }
+    return (&res);
+} /* signal_sfs_1 */
+
+
+/* sfs_m_msg.c */
diff --git a/TBBT/trace_play/sfs_m_prm.c b/TBBT/trace_play/sfs_m_prm.c
new file mode 100644 (file)
index 0000000..5cc5ac3
--- /dev/null
@@ -0,0 +1,1545 @@
+#ifndef lint
+static char sccsid[] = "@(#)sfs_m_prm.c        2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * This program is started from sfs_mgr.  It runs on some system
+ * designated as the Prime Client and synchronizes the the different
+ * phases of a SFS benchmark execution amongst multiple clients by
+ * means of RPCs.  The Prime client can also be running SFS.
+ *
+ *.Exported_routines
+ *     int main(int, char **)
+ *
+ *.Local_routines
+ *     void multi_cleanup(int)
+ *     void do_initialize(int, char **)
+ *     void sync_PC_with_clients(void)
+ *     int signal_sfs_clients(char *, int)
+ *     void print_multi_results(void)
+ *     void prog_usage(void)
+ *     void printdeadclients(void)
+ *
+ *.Revision_history
+ *     11-Jul-94       ChakChung Ng    Add codes for NFS/v3
+ *      02-Jul-92      0.1.9   Teelucksingh
+ *                             Use tcp handles for synchronization
+ *                             instead of udp ones. Added code to make
+ *                              call to shell script to start and stop
+ *                             external monitoring (no longer creates
+ *                             /tmp/SFS_START and /tmp/SFS_DONE).
+ *     10-Jan-92       0.00.19 Teelucksingh
+ *                             Added code for the Prime-Client to report
+ *                             'INVALID RUN' from any of the clients.
+ *                             Also added code to compute and report
+ *                             the aggregate 'average response time
+ *                             standard deviation values'.
+ *     04-Jan-92       0.00.18 Pawlowski
+ *                             Add hooks for raw data dump support.
+ *     04-Dec-91       0.00.15 Keith
+ *                             Include string.h for SYSV/SVR4
+ *     28-Nov-91       0.00.13 Teelucksingh
+ *                             Fixed 'multiple signals' problem.
+ *                             Sync rpcs now pass a 'transaction id'
+ *                             to 'sfs_syncd', the sync server.
+ *                             'sfs_syncd' keeps track of previous rpc
+ *                             calls that successfully executed.
+ *                             Added ANSI C features.
+ *
+ *      23-Sep-91      0.00.11 Teelucksingh
+ *                              Modified the format of sfs_prime output
+ *     17-Jun-91       Teelucksingh    Created.
+ *
+ *
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/file.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+#if !defined(_XOPEN_SOURCE)
+#include <sys/socket.h>
+#else
+#define        AF_INET         2
+#endif
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+
+
+/* sfs_mpr.c function declarations */
+/* external sfs routines */
+
+/* forward definitions for local routines */
+static void multi_cleanup(int);
+static void do_initialize(int, char **);
+static void sync_PC_with_clients(void);
+static int signal_sfs_clients(char *);
+static void print_multi_results(void);
+static void prog_usage(void);
+static void printdeadclients(void);
+
+/*
+ * -----------------------  Static Definitions  -----------------------
+ */
+
+#define EXTRA_INIT_TIME 3600  /* extra time to initialize before timing out */
+
+int Debug_level = 0;           /* flag indicates prime client debug mode */
+char *sfs_Myname;                      /* program name */
+int nfs_version;
+
+static int Asleep = 0;         /* flag: parent sfs process is asleep */
+static int Pc_log_fd;                 /* Prime client sync log fd */
+static int Num_clients = 0;           /* number of clients used in run */
+static char **Client_names; /* [HOSTNAME_LEN];   array of clients host names */
+                            /* sleep period before issuing a go ahead signal */
+static int Prime_sleep_time = 0;
+                            /* time to wait before exiting with error */
+static int Prime_time_out = 400;
+static int Prime_runtime = DEFAULT_RUNTIME; /* seconds in benchmark run */
+
+/*
+ * the Prime_client only uses the P_* variables
+ * for calculating and reporting the Aggregate
+ * run parameters.
+ */
+static int P_children = DEFAULT_NPROCS; /* processes per client */
+static int P_total_load = DEFAULT_LOAD; /* NFS operations per second */
+static int P_percent_append = DEFAULT_APPEND; /* % of writes that append */
+static int P_percent_access = DEFAULT_ACCESS; /* % of file set accessed */
+static int P_kb_per_block = DEFAULT_KB_PER_BLOCK; /* i/o pkt block sz in KB */
+static int P_dump_data = 0;            /* raw output switch */
+static int P_testop = -1;              /* test mode operation number */
+static int P_percent_fss_delta =       /* allowed change to file set */
+                               DEFAULT_DELTA_FSS;
+                                       /* allowed change to file set */
+static int P_warmuptime = DEFAULT_WARMUP; /* seconds to warmup */
+static char *P_iodist_file = 0;                /* block io dist table file */
+static char *P_mix_file = 0;           /* mix file */
+static char *P_script_name = 0;                /* external script name */
+static char *P_script_args = "";       /* external script parameters */
+static int P_tcp = 0;                  /* TCP */
+static FILE *sum_result_fp = NULL;
+
+/*
+ * ---------------------  Biod Simulation Variables ---------------------
+ */
+static int P_biod_max_outstanding_reads = DEFAULT_BIOD_MAX_READ;
+static int P_biod_max_outstanding_writes = DEFAULT_BIOD_MAX_WRITE;
+
+/* list of nfs operations - used to verify results file */
+static char *Ops_name[NOPS] = {        "null", "getattr", "setattr", "root", "lookup",
+                               "readlink", "read", "wrcache", "write",
+                               "create", "remove", "rename", "link",
+                               "symlink", "mkdir", "rmdir", "readdir",
+                               "fsstat", "access", "commit", "fsinfo",
+                               "mknod", "pathconf", "readdirplus" };
+
+
+/*
+ * --------------------------  Prime-client  --------------------------
+ */
+
+
+/*
+ * SIGINT Signal Handler
+ * - rpc to all clients to cleanup and exit
+ */
+static void
+multi_cleanup(
+    int                sig_id)
+{
+    /* wake up this process if asleep */
+    if (Asleep == 1) {
+       (void) generic_kill(0,SIGALRM);
+    }
+    (void) fprintf(stderr,"\n%s: Caught Signal %d SIGINT\n", sfs_Myname, sig_id);
+    (void) fprintf(stderr,"\nSending interupt signal to clients ... ");
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_STOP") !=0)
+       exit(9);
+    (void) fprintf(stderr,"done\n");
+    (void) fflush(stderr);
+    (void) close(Pc_log_fd);
+    (void) unlink(SFS_PRIME_SYNC_LOG);
+    exit(10);
+
+} /* multi_cleanup */
+
+
+/*
+ * main
+ * synchronizes multi-client sfs run
+ * - wait for 'DONE-MOUNT' from all clients
+ * - tell them to `DO-INIT`
+ * - wait for `DONE-INIT` from all clients
+ * - tell them to `DO-WARMUP`
+ * - wait for 'READY from all clients
+ * - tells them to 'START' and goes to sleep
+ * - wakes up and tells clients to 'STOP'
+ * - wait for 'DONE-TEST' from all clients
+ * - tells clients to 'MOVE-DATA'
+ * - averages multi-client data and exits
+ */
+int
+main(
+    int                argc,
+    char *     argv[])
+{
+    int                i;
+    char       monitor_cmd[SFS_MAXPATHLEN+5];
+    int                nsigs = 32;             /* reasonable default */
+    FILE       *pid_fp;
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    struct sigaction sig_act, old_sig_act;
+#endif
+
+    /*
+     * Place pid in pid log file
+     */  
+    if ((pid_fp = fopen(SFS_PRM_PID, "a+")) == NULL) {
+        perror(SFS_PRM_PID);
+        exit(1);
+    }
+    (void) fprintf(pid_fp, "%d\n", getpid());
+    (void) fclose(pid_fp);
+
+    (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
+                                SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fflush(stderr);
+
+    /* initialize variables, parse input, etc.  */
+    do_initialize(argc, argv);
+
+    /*
+     * setup value of nsigs
+     */
+#ifdef __NSIG
+    nsigs = __NSIG;
+#endif
+#ifdef _NSIG
+    nsigs = _NSIG;
+#endif
+#ifdef NSIG
+    nsigs = NSIG;
+#endif
+#if defined(SOLARIS2) && !defined(_sys_nsig)
+    nsigs = _sys_siglistn;
+#endif
+
+    /* trap for all signals */
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    /* use XOPEN signal handling */
+    sig_act.sa_handler = generic_catcher;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+    if (DEBUG_PARENT_GENERAL) {
+       if (nsigs == 0) {
+           (void) fprintf (stderr,
+                   "WARNING: nsigs not defined, no extra signals caught\n");
+       }
+       for (i = 1; i < nsigs; i++) {
+     /* attempt to set up signal handler for these signals gives an error. */
+           if (i!=SIGCHLD && i!=SIGKILL && i!=SIGSTOP && i!=SIGCONT) {
+                if (sigaction(i,&sig_act,&old_sig_act) == -1) {
+                        if (errno == EINVAL)
+                                (void) fprintf (stderr,
+                                       "Skipping invalid signal %d\n", i);
+                        else {
+                                perror("sigaction failed");
+                                exit(11);
+                        }
+                }
+           }
+       }
+    }
+
+    /* signals handlers for signals used by sfs_prime */
+    sig_act.sa_handler = multi_cleanup;
+    if (sigaction(SIGINT,&sig_act,&old_sig_act) != 0) {
+               perror("sigaction failed: SIGINT");
+               exit(12);
+    }
+#else
+
+    if (DEBUG_PARENT_GENERAL) {
+       if (nsigs == 0) {
+           (void) fprintf (stderr,
+                   "WARNING: nsigs not defined, no extra signals caught\n");
+       }
+       for (i = 1; i < nsigs; i++) {
+           (void) signal(i, generic_catcher);
+       }
+    }
+
+    /* set up SIGINT signal handler */
+    (void) signal(SIGINT, multi_cleanup);
+
+#endif /* USE_POSIX_SIGNALS */
+
+    (void) fprintf(stderr, "Executing SFS Benchmark on %d Client(s).\n",
+                   Num_clients);
+    (void) fflush(stderr);
+
+    /* wait for 'DONE-MOUNT message from the clients */
+    (void) fprintf(stderr,
+          "%s Waiting on DONE-MOUNT message from %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+
+    sync_PC_with_clients();             /* wait for clients DONE-MOUNT */
+
+    (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* send DO-INIT message to all the clients  */
+    (void) fprintf(stderr, "%s Sending DO-INIT message to %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
+       exit(13);
+    (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* wait for 'DONE-INIT' message from the clients */
+    (void) fprintf(stderr,
+          "%s Waiting on DONE-INIT message from %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+
+    /*
+     * add an extra time to time_out value.
+     * initializing the SFS testdirs on clients can take a while.
+     */
+    Prime_time_out += EXTRA_INIT_TIME;
+    sync_PC_with_clients();             /* wait for clients DONE-INIT */
+    Prime_time_out -= EXTRA_INIT_TIME;        /* reset time_out */
+
+    (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* send DO-WARMUP message to all the clients  */
+    (void) fprintf(stderr, "%s Sending DO-WARMUP message to %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
+       exit(14);
+    (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* wait for 'READY' message from the clients */
+    (void) fprintf(stderr, "%s Waiting on READY message from %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+
+    (void) sleep(P_warmuptime);
+
+    sync_PC_with_clients();            /* wait for clients READY */
+
+    (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /*
+     * call the program to trigger START of external monitoring
+     */
+     if (P_script_name) {
+       (void) sprintf(monitor_cmd,"%s %s %s",P_script_name,
+                       "START",P_script_args);
+       if (system(monitor_cmd) != 0) {
+               (void) fprintf(stderr,"%s: external monitoring command (%s) failed - %d - continuing.\n ",
+                       sfs_Myname, monitor_cmd, errno);
+               (void) fflush(stderr);
+               P_script_name = NULL;
+       }
+
+     }
+
+    /*
+     * wait period before telling clients to START - gives external
+     * performance monitoring utilities enough time to start up.
+     * Value set in sfs_rc (PRIME_SLEEP) - default is 0 seconds.
+     */
+    (void) sleep(Prime_sleep_time);
+
+    /* send START message to all the clients  */
+    (void) fprintf(stderr, "%s Sending START message to %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
+       exit(15);
+    (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /*
+     * Sleep for <Prime_runtime> seconds
+     * and then send STOP message to tell the sfs clients
+     * that is time to wrap things up.
+     */
+    /* set the Asleep flag go to sleep while clients are executing sfs */
+    Asleep = 1;
+    (void) sleep(Prime_runtime);
+    Asleep = 0;
+
+    (void) fprintf(stderr, "%s Sending STOP message to %d client(s).\n",
+                       lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_ALARM") !=0)
+       exit(16);
+    (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+
+    /* wait for DONE-TEST message from clients indicating they completed run */
+    (void) fprintf(stderr, "%s Waiting on DONE-TEST message from %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    sync_PC_with_clients();
+    (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /*
+     * call the program to trigger STOP of external monitoring
+     */
+     if (P_script_name) {
+       (void) sprintf(monitor_cmd,"%s %s %s",P_script_name,
+                       "DONE",P_script_args);
+       if (system(monitor_cmd) != 0) {
+               (void) fprintf(stderr,"%s: external monitoring command (%s) failed - %d - continuing.\n ",
+                       sfs_Myname, monitor_cmd, errno);
+               (void) fflush(stderr);
+               P_script_name = NULL;
+       }
+     }
+
+    /* give enough time to stop external performance monitoring utilities.  */
+    (void) sleep(Prime_sleep_time);
+
+    /*
+     * send MOVE-DATA message to Clients to move data across
+     */
+    (void) fprintf(stderr, "%s Sending MOVE-DATA message to %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
+       exit(17);
+    (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* wait for SEND-DATA message from all the clients */
+    (void) fprintf(stderr,
+                   "%s Waiting on SEND-DATA message from %d client(s).\n",
+                   lad_timestamp(), Num_clients);
+    (void) fflush(stderr);
+    sync_PC_with_clients();
+    (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
+    (void) fflush(stderr);
+
+    /* summarize and print aggregate results */
+    print_multi_results();
+
+    /* close files and exit success */
+    (void) close(Pc_log_fd);
+    (void) unlink(SFS_PRIME_SYNC_LOG);
+    (void) unlink(SFS_PRM_PID);
+    return(0);
+
+}  /* main */
+
+/*
+ * initialize control variables, open logfiles etc.
+ */
+static void
+do_initialize(
+    int                argc,
+    char       *argv[])
+{
+    int                c;
+    FILE       *check_fp;
+    int i;
+    char       *cp;
+    extern char *optarg;
+    extern int optind;
+
+
+    sfs_Myname = argv[0];
+    if (argc <= 1) {
+       prog_usage();
+       /* NOTREACHED */
+    }
+
+    while ((c = getopt(argc, argv, "a:A:b:B:C:d:f:k:K:l:m:p:QR:s:t:T:W:w:x:z")) != EOF)
+       switch (c) {
+       case 'a': /* Percent of file set to access;
+                  * used in aggregate report.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal acces value %s\n",
+                                       sfs_Myname, optarg);
+               exit(18);
+           }
+           P_percent_access = atoi(optarg);
+           if (P_percent_access < 0 || P_percent_access > 100) {
+               (void) fprintf(stderr,
+                      "%s: %% access must be between 0 and 100\n",
+                       sfs_Myname);
+               exit(19);
+           }
+           break;
+
+       case 'A': /* Percent of writes that append;
+                  * used in aggregate report.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal append value %s\n",
+                                       sfs_Myname, optarg);
+               exit(20);
+           }
+           P_percent_append = atoi(optarg);
+           if (P_percent_append < 0 || P_percent_append > 100) {
+               (void) fprintf(stderr,
+                              "%s: %% append must be between 0 and 100\n",
+                               sfs_Myname);
+               exit(21);
+           }
+           break;
+
+       case 'b': /* Set block size distribution table file
+                  * used in aggregate report.
+                  */
+           if ((check_fp = fopen(optarg, "r")) == NULL) {
+               cp = strerror(errno);
+               (void) fprintf(stderr, "%s: bad block size file %s: %s\n",
+                                       sfs_Myname, optarg, cp);
+               exit(22);
+           }
+           P_iodist_file = optarg;
+           (void) fclose(check_fp);
+           break;
+
+
+       case 'B': /* Set the per packet maximum block size
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal block size value %s\n",
+                                       sfs_Myname, optarg);
+               exit(23);
+           }
+           P_kb_per_block = atoi(optarg);
+           if ((P_kb_per_block < 1) ||
+                       (P_kb_per_block > (DEFAULT_MAX_BUFSIZE/1024))) {
+               (void) fprintf(stderr, "%s: illegal block size value %s\n",
+                                       sfs_Myname, optarg);
+               exit(24);
+           }
+           break;
+
+       case 'C': /*
+                  * Set summary result file
+                  */
+            if ((sum_result_fp = fopen(optarg, "a+")) == NULL) {
+               cp = strerror(errno);
+               (void) fprintf(stderr,
+                       "%s: Unable to create summary result file %s: %s\n",
+                                       sfs_Myname, optarg, cp);
+               exit(222);
+           }
+           break;
+
+       case 'd': /*
+                  * Set Debug_level
+                  */
+           Debug_level = set_debug_level(optarg);
+           break;
+
+       case 'f': /* Percent change in file set size
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal file set delta value %s\n",
+                                       sfs_Myname, optarg);
+               exit(26);
+           }
+           P_percent_fss_delta = atoi(optarg);
+           if (P_percent_fss_delta < 0 || P_percent_fss_delta > 100) {
+               (void) fprintf(stderr,
+                          "%s: %% file set delta must be between 0 and 100\n",
+                           sfs_Myname);
+               exit(27);
+           }
+           break;
+
+       case 'k': /*
+                  * program to start and stop external
+                  * performance monitoring. Called at start
+                  * and completion of core load generation period.
+                  */
+           if ((check_fp = fopen(optarg, "r")) == NULL) {
+               cp = strerror(errno);
+               (void) fprintf(stderr,
+                       "%s: program %s protected or missing: %s\n",
+                       sfs_Myname, optarg, cp);
+               exit(28);
+           }
+           P_script_name = optarg;
+           (void) fclose(check_fp);
+           break;
+
+       case 'K': /*
+                  * Command-line parameters for the external monitor
+                  * (see the "-k" option, above)
+                  */
+           P_script_args = optarg;
+           break;
+
+       case 'l': /* Set load
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal load value %s\n",
+                                       sfs_Myname, optarg);
+               exit(29);
+           }
+           P_total_load = atoi(optarg);
+           if (P_total_load < 0) {
+               (void) fprintf(stderr, "%s: load must be > 0\n", sfs_Myname);
+               exit(30);
+           }
+           break;
+
+       case 'm': /* Set mix from a file
+                  * used in aggregate reporting only.
+                  */
+           if ((check_fp = fopen(optarg, "r")) == NULL) {
+               cp = strerror(errno);
+               (void) fprintf(stderr, "%s: bad mix file: %s: %s\n",
+                               sfs_Myname, optarg, cp);
+               exit(31);
+           }
+           P_mix_file = optarg;
+           (void) fclose(check_fp);
+           break;
+
+       case 'p': /* Set number of child processes
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal procs value %s\n",
+                                       sfs_Myname, optarg);
+               exit(32);
+           }
+           P_children = atoi(optarg);
+           if (P_children < 0) {
+               (void) fprintf(stderr, "%s: number of children must be > 0\n",
+                               sfs_Myname);
+               exit(33);
+           }
+           break;
+
+       case 'Q': /* Set NFS/TCP behaviour */
+           P_tcp = 1;
+           break;
+
+       case 'R': /* set maximum async read concurrency level
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal read count value %s\n",
+                               sfs_Myname, optarg);
+               exit(34);
+           }
+           P_biod_max_outstanding_reads = atoi(optarg);
+           if (P_biod_max_outstanding_reads < 0) {
+               (void) fprintf(stderr, "%s: read count must be >= 0\n",
+                               sfs_Myname);
+               exit(35);
+           }
+           break;
+
+       case 's':
+            /*
+             * Set sleep time so external processes will
+             * have time to startup
+             */
+             if (!isdigit(optarg[0])) {
+                 (void) fprintf(stderr, "%s: illegal sleep value %s\n",
+                                 sfs_Myname, optarg);
+                 exit(36);
+             }
+             Prime_sleep_time = atoi(optarg);
+             break;
+
+       case 't': /* Set SFS Runtime value */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal time value %s\n",
+                               sfs_Myname, optarg);
+               exit(37);
+           }
+           Prime_runtime = atoi(optarg);
+           if (Prime_runtime < 0) {
+               (void) fprintf(stderr, "%s: run time must be >= 0\n",
+                               sfs_Myname);
+               exit(38);
+           }
+           break;
+
+       case 'T': /* Set Test mode operation
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal time_out value %s\n",
+                               sfs_Myname, optarg);
+              exit(39);
+           }
+           P_testop = atoi(optarg);
+           if (P_testop >= NOPS) {
+               (void) fprintf(stderr, "%s: illegal test value %d\n",
+                                       sfs_Myname, P_testop);
+               exit(40);
+           }
+           break;
+
+       case 'W': /* set maximum async write concurrency level
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal write count value %s\n",
+                                       sfs_Myname, optarg);
+               exit(41);
+           }
+           P_biod_max_outstanding_writes = atoi(optarg);
+           if (P_biod_max_outstanding_writes < 0) {
+               (void) fprintf(stderr, "%s: write count must be >= 0\n",
+                               sfs_Myname);
+               exit(42);
+           }
+           break;
+
+       case 'w': /* Set warmup time
+                  * used in aggregate reporting only.
+                  */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr, "%s: illegal warmup value %s\n",
+                               sfs_Myname, optarg);
+               exit(43);
+           }
+           P_warmuptime = atoi(optarg);
+           if (P_warmuptime < 0) {
+               (void) fprintf(stderr, "%s: warmup time must be >= 0\n",
+                               sfs_Myname);
+               exit(44);
+           }
+           break;
+
+       case 'x': /* Set Prime-Client time_out value */
+           if (!isdigit(optarg[0])) {
+               (void) fprintf(stderr,
+                               "%s: illegal time_out value %s\n",
+                               sfs_Myname, optarg);
+              exit(45);
+           }
+           Prime_time_out = atoi(optarg);
+           break;
+
+       case 'z': /* Do raw data dumps
+                  *  used in aggregate reporting only.
+                  */
+           P_dump_data++;
+           break;
+
+       default:
+           prog_usage();
+           /* NOTREACHED */
+       } /* end switch on argument */
+
+    Num_clients = argc - optind;
+
+    /*
+     * allocate space and store clients names
+     */
+    Client_names = (char **) malloc(Num_clients * sizeof(char *));
+    if (Client_names == (char **) 0) {
+       (void) fprintf(stderr, "%s: client name malloc %d bytes failed",
+                   sfs_Myname, Num_clients * sizeof(char **));
+       exit(46);
+    }
+
+    for (i = 0; optind < argc; i++, optind++) {
+       Client_names[i] = argv[optind];
+       if (gethostbyname(argv[optind]) == NULL) {
+           (void) fprintf(stderr, "\n%s: unknown client - %s\n",
+                       sfs_Myname, argv[optind]);
+           exit(47);
+       }
+    }
+
+    if (sum_result_fp == NULL)
+       sum_result_fp = stdout;
+
+    Pc_log_fd = open(SFS_PRIME_SYNC_LOG, (O_RDWR | O_CREAT), 0666);
+    if (Pc_log_fd == -1) {
+       perror(SFS_PRIME_SYNC_LOG);
+       exit(48);
+    }
+
+} /* do_initialize */
+
+
+/*
+ * Small utility routine to pretty print out the names
+ * of the clients which did not respond to the message.
+ */
+static void
+printdeadclients(void)
+{
+    int        *clients;
+    int client;
+    int i;
+    FILE *fd;
+
+    if ((clients = (int *)malloc(sizeof(int) * Num_clients)) == NULL) {
+       (void) fprintf(stderr, "%s: malloc failed\n", sfs_Myname);
+       (void) fflush(stderr);
+       return;
+    }
+
+    for (i = 0; i < Num_clients; i++) {
+       clients[i] = 0;
+    }
+
+    fd = fopen(SFS_PRIME_SYNC_LOG, "r");
+    if (fd == NULL) {
+       (void) fprintf(stderr,"%s: Cannot open %s\n",
+           sfs_Myname, SFS_PRIME_SYNC_LOG);
+       (void) fflush(stderr);
+       return;
+    }
+
+    while(fread(&client, sizeof(int), 1, fd) == 1) {
+       if (client > 0 && client <= Num_clients)
+               clients[client - 1] = 1;
+    }
+
+    for (i = 0; i < Num_clients; i++) {
+       if (clients[i] == 0) {
+           (void) fprintf(stderr, "\n%s: Did not get signal from client %s\n",
+                   sfs_Myname, Client_names[i]);
+           (void) fflush(stderr);
+       }
+    }
+    (void) fclose(fd);
+    free (clients);
+}
+
+/*
+ * monitor Logfile until all Clients write to it.
+ *
+ * Each client appends its client id to the file. So the size
+ * of the log file divided by sizeof(int) is the number of
+ * clients that have responded.
+ */
+static void
+sync_PC_with_clients(void)
+{
+    struct stat                statb;          /* for fstat */
+    int                        num_secs;       /* keep count of time */
+    int                        clientsremaining;
+
+    num_secs = 0;
+    do {
+       (void) sleep(1);
+       if (fstat(Pc_log_fd, &statb) == -1) {
+           (void) fprintf(stderr, "%s: can't stat Prime Client log %s",
+                                   sfs_Myname, SFS_PRIME_SYNC_LOG);
+           exit(49);
+       }
+       num_secs++;
+       clientsremaining = Num_clients - (statb.st_size / sizeof(int));
+    } while ( (clientsremaining > 0) && (num_secs < Prime_time_out));
+
+    /* if clients not responding then terminate experiment */
+    if (clientsremaining > 0) {
+       (void) fprintf(stderr,
+       "\n%s: Prime Client timeout - did not get signal from %d client(s)\n",
+                       sfs_Myname, clientsremaining);
+       printdeadclients();
+       /* send message to clients to stop */
+       (int) signal_sfs_clients("PRIME_STOP");
+       exit(50);
+    }
+
+    /* if more clients than exist responded then syncd is telling us to exit */
+    if (clientsremaining < 0) {
+       (void) fprintf(stderr,
+       "\n%s: Prime Client got too many signals - expected %d got %ld\n",
+               sfs_Myname, Num_clients, statb.st_size / sizeof(int));
+       /* send message to clients to stop */
+       (int) signal_sfs_clients("PRIME_STOP");
+       exit(51);
+    }
+
+    /* success, so go ahead and truncate the sync logfile */
+    (void)close(Pc_log_fd);
+    Pc_log_fd = open(SFS_PRIME_SYNC_LOG,
+                       (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
+    if (Pc_log_fd == -1) {
+       /* problem in truncating sync logfile - stop experiment */
+       (void) fprintf(stderr, "%s: can't truncate Prime Client log %s",
+                      sfs_Myname, SFS_PRIME_SYNC_LOG);
+       (void) fflush(stderr);
+       (int) signal_sfs_clients("PRIME_STOP");
+       exit(52);
+    }
+
+} /* sync_PC_with_clients */
+
+
+#ifdef CLOSE_CLNT_HANDLE
+static int close_clnt_handle = 1;
+#else
+static int close_clnt_handle = 0;
+#endif
+/*
+ * makes RPC to all clients, dependent on message
+ * Save the client handles to keep from doing unnecessary portmapper calls.
+ * This can help if we have to route through the busy server.
+ */
+static int
+signal_sfs_clients(char *message)
+{
+    static int Transac_num = 0;            /* transaction number */
+    static CLIENT **   sfs_clnt_handle = NULL;
+    static int         *sfs_socket = NULL;
+    int *              result;
+    int                        i;
+    sync_string                sync_signal;
+    char               transaction_string[MAX_STR1_LEN];
+
+    (void) sprintf(transaction_string,"Prime_%i",++Transac_num);
+    sync_signal.clnt_type = message;
+    sync_signal.clnt_data = "";
+    sync_signal.clnt_transaction = transaction_string;
+
+    if (sfs_clnt_handle == NULL) {
+       sfs_socket = (int *) calloc(Num_clients, sizeof(int));
+       if (sfs_socket == (int *) 0) {
+          (void) fprintf(stderr, "%s: socket malloc failed.\n",
+                         sfs_Myname);
+          exit(53);
+       }
+
+       /* allocate space for tcp handles */
+       sfs_clnt_handle =  (CLIENT **) calloc(Num_clients, sizeof(CLIENT));
+       if (sfs_clnt_handle == (CLIENT **)0 ) {
+            (void) fprintf(stderr, "%s: clnttcp_create out of memory\n",
+                       sfs_Myname);
+            exit(54);
+       }
+    }
+
+    /* set up the tcp handles for all the clients */
+    for (i = 0; i < Num_clients; i++) {
+       if (sfs_clnt_handle[i] == NULL) {
+           struct hostent      *host_info;
+           struct sockaddr_in  clnt_addr;
+#ifdef SUNOS
+           int fd;
+#endif
+
+           sfs_socket[i] = RPC_ANYSOCK;
+
+           if ((host_info = gethostbyname(Client_names[i])) == NULL)
+                return((int) RPC_UNKNOWNHOST);
+           (void) memset((char *) &clnt_addr, '\0', sizeof(clnt_addr));
+           (void) memmove((char *) &clnt_addr.sin_addr,
+                               (char *) host_info->h_addr,
+                               host_info->h_length);
+           clnt_addr.sin_family = AF_INET;
+           clnt_addr.sin_port =  0;
+
+           /*
+            * Create client "handle" used for calling CL_MESSAGEPROG on the
+            * sfs client(s). We tell the RPC package to use the "tcp"
+            * protocol when contacting the clients.
+            */
+           sfs_clnt_handle[i] = clnttcp_create(&clnt_addr, SFS_SYNCPROG,
+                                       SFS_SYNCVERS, &sfs_socket[i],
+                                       MAX_STR2_LEN, MAX_STR2_LEN);
+
+           if (sfs_clnt_handle[i] == (CLIENT *) NULL) {
+               /*
+                * Couldn't establish connection with the sfs Client.
+                * print error message and return status
+                */
+               clnt_pcreateerror(Client_names[i]);
+               return((int) RPC_FAILED);
+           }
+#ifdef SUNOS
+           /*
+            * Some commands in 4.X will fail if there are too many file
+            * descriptors open, if the sfs_ext_mon uses one
+            * of those then it will fail.  We set the close-on-exec
+            * flag to help them.
+            */
+           if (clnt_control(sfs_clnt_handle[i], CLGET_FD, (char *)&fd) ==
+                       FALSE) {
+               clnt_pcreateerror(Client_names[i]);
+               return((int) RPC_FAILED);
+           }
+           if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+               perror("F_SETFD");
+               return((int) RPC_FAILED);
+           }
+#endif
+       } /* end no client handle */
+
+       /*
+        * Call the remote procedure "signal_sfs_cl_1" on each of the clients
+        * pass the client number so sfs_syncd will know which client files
+        * to look for in a shared /tmp area
+        */
+       sync_signal.clnt_id = i + 1;
+       result = signal_sfs_1(&sync_signal, sfs_clnt_handle[i]);
+
+       if (result == NULL) {
+           /* Error occurred.  Print error message and return error. */
+           clnt_perror(sfs_clnt_handle[i], Client_names[i]);
+           return((int) RPC_CANTSEND);
+       }
+
+       /* Okay, we successfully called the remote procedure.  */
+       if (*result == 0) {
+           /*
+            * remote procedure was unable to write to its sync file.
+            * Print error message and return failure.
+            */
+           (void) fprintf(stderr,
+                       "\n%s: Unable to perform remote procedure on %s . \n",
+                           sfs_Myname, Client_names[i]);
+           (void) fflush(stderr);
+           return((int) RPC_FAILED);
+       }
+       if (close_clnt_handle) {
+               clnt_destroy(sfs_clnt_handle[i]);
+               sfs_clnt_handle[i] = NULL;
+       }
+    } /* end for each client */
+
+    return(0);
+
+} /* signal_sfs_clients */
+
+
+/*
+ * summarize and print multi-client results
+ */
+static void
+print_multi_results(void)
+{
+    FILE *     fd;             /* results files */
+    int        i;
+    int                k;
+    char       res_file[SFS_MAXPATHLEN];               /* results filename */
+    char       str[MAX_LINE_LEN];
+
+    double     stdev_msec, var_msec;
+    float      tot_squared_time_msec, tot_sum2_msec;
+    float      tot_got, tot_secs, tot_msec_calls, tot_res_time;
+    int                tot_want, tot_calls, tot_errors;
+
+    double     sq_conf_interval_msec;
+    double     conf_interval_msec;
+    int                totals;
+    int                invalid = 0;
+
+#define MAXOPNAME      19
+    struct client_stats {
+       /* First line */
+       int     version;
+       int     num_io_files;
+       int     num_access_io_files;
+       int     num_non_io_files;
+       int     num_symlinks;
+       int     num_dirs;
+       /* NOPS lines */
+       struct client_op_stats {
+               char    op[MAXOPNAME];
+               int     want;
+               float   got;
+               int     calls;
+               int     errors;
+               float   secs;
+               float   msec_calls;
+               float   res_time;
+               float   squared_time_msec;
+               float   sum2_msec;
+       } op_stats[NOPS];
+       /* Last line */
+       float   sum_calls_sec;
+       float   sum_msec_calls;
+       int     sum_secs;
+       int     sum_calls;
+       int     client_invalid_flag;
+       uint32_t total_fss_bytes;
+       uint32_t least_fss_bytes;
+       uint32_t most_fss_bytes;
+       uint32_t base_fss_bytes;
+    } *client_stats;
+
+
+    /*
+     * malloc space for statistics
+     *  Note last entry is for running totals.
+     */
+     client_stats = (struct client_stats *) calloc(Num_clients+1,
+                                               sizeof(struct client_stats));
+     if (client_stats == (struct client_stats *)0) {
+       (void) fprintf(stderr, "%s: client_stats malloc failed.\n",
+                     sfs_Myname);
+       (void) fflush(stderr);
+       exit(55);
+     }
+
+    totals = Num_clients;
+    /*
+     * Read each client file one at a time gathering statistics
+     */
+    for (i = 0; i < Num_clients;i++) {
+       (void) sprintf(res_file, "%s%i", PRIME_RESULTS_LOG, i + 1);
+       fd = fopen(res_file, "r");
+       if (fd == (FILE *)NULL) {
+           (void) fprintf(stderr, "%s: Cannot open results file - %s\n",
+                           sfs_Myname, res_file);
+           (void) fflush(stderr);
+           exit(56);
+       }
+
+       /*
+        * the SFS clients compute its File set info. at runtime;
+        * the clients pass back the computed value in the results
+        * (RPC) info. Get the fileset info used by the clients and compute
+        * the aggregate value.
+        */
+       if (fgets(str, MAX_LINE_LEN, fd) == NULL) {
+           (void) fprintf(stderr,"%s: can't read data in results file - %s\n",
+                               sfs_Myname, res_file);
+           (void) fflush(stderr);
+           exit(57);
+       }
+       if (sscanf(str,"%d %d %d %d %d %d",
+                               &client_stats[i].version,
+                               &client_stats[i].num_io_files,
+                               &client_stats[i].num_access_io_files,
+                               &client_stats[i].num_non_io_files,
+                               &client_stats[i].num_symlinks,
+                               &client_stats[i].num_dirs) != 6) {
+           (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
+                               sfs_Myname, res_file);
+           (void) fflush(stderr);
+           exit(58);
+       }
+
+       client_stats[totals].num_io_files += client_stats[i].num_io_files;
+       client_stats[totals].num_access_io_files +=
+                                       client_stats[i].num_access_io_files;
+       client_stats[totals].num_non_io_files +=
+                                       client_stats[i].num_non_io_files;
+       client_stats[totals].num_symlinks +=
+                                       client_stats[i].num_symlinks;
+       client_stats[totals].num_dirs += client_stats[i].num_dirs;
+
+       /* Gather per operation statistics */
+       for (k = 0; k < NOPS; k++) {
+           if (fgets(str, MAX_LINE_LEN, fd) == NULL) {
+               (void) fprintf(stderr,
+                               "%s: can't read data in results file - %s\n",
+                               sfs_Myname, res_file);
+               (void) fflush(stderr);
+               exit(59);
+           }
+           if (sscanf(str, "%s %d%% %f%% %d %d %f %f %f%% %f %f",
+                       client_stats[i].op_stats[k].op,
+                       &client_stats[i].op_stats[k].want,
+                       &client_stats[i].op_stats[k].got,
+                       &client_stats[i].op_stats[k].calls,
+                       &client_stats[i].op_stats[k].errors,
+                       &client_stats[i].op_stats[k].secs,
+                       &client_stats[i].op_stats[k].msec_calls,
+                       &client_stats[i].op_stats[k].res_time,
+                       &client_stats[i].op_stats[k].squared_time_msec,
+                       &client_stats[i].op_stats[k].sum2_msec) != 10) {
+               (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
+                               sfs_Myname, res_file);
+               (void) fflush(stderr);
+               exit(60);
+           }
+           if (strcmp(client_stats[i].op_stats[k].op,Ops_name[k]) != 0) {
+               (void) fprintf(stderr, "%s: bad data in results file\n",
+                                   sfs_Myname);
+               (void) fflush(stderr);
+               exit(61);
+           }
+       }
+
+       if (fgets(str, 100, fd) == NULL) {
+           (void) fprintf(stderr,"%s: can't read data in results file - %s\n",
+                               sfs_Myname, res_file);
+               (void) fflush(stderr);
+           exit(62);
+       }
+       if (sscanf(str,"%f %f %d %d %d %u %u %u %u",
+               &client_stats[i].sum_calls_sec,
+               &client_stats[i].sum_msec_calls,
+               &client_stats[i].sum_secs,
+               &client_stats[i].sum_calls,
+               &client_stats[i].client_invalid_flag,
+               &client_stats[i].total_fss_bytes,
+               &client_stats[i].least_fss_bytes,
+               &client_stats[i].most_fss_bytes,
+               &client_stats[i].base_fss_bytes) != 9) {
+           (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
+                               sfs_Myname, res_file);
+           (void) fflush(stderr);
+           exit(63);
+       }
+
+       client_stats[totals].sum_secs += client_stats[i].sum_secs;
+       client_stats[totals].sum_calls += client_stats[i].sum_calls;
+       client_stats[totals].sum_calls_sec +=
+                                       client_stats[i].sum_calls_sec;
+       client_stats[totals].sum_msec_calls +=
+                                       client_stats[i].sum_msec_calls;
+       client_stats[totals].total_fss_bytes +=
+                                       client_stats[i].total_fss_bytes;
+       client_stats[totals].least_fss_bytes +=
+                                       client_stats[i].least_fss_bytes;
+       client_stats[totals].most_fss_bytes +=
+                                       client_stats[i].most_fss_bytes;
+       client_stats[totals].base_fss_bytes +=
+                                       client_stats[i].base_fss_bytes;
+
+       (void) fclose(fd);
+    } /* for Num_clients */
+
+    nfs_version = client_stats[0].version;
+
+    /*
+     * print the aggregate test parameters
+     */
+    (void) fprintf(stdout, "\nAggregate Test Parameters: \n");
+    (void) fprintf(stdout, "    Number of processes = %d\n",
+                  P_children * Num_clients);
+    (void) fprintf(stdout, "    Requested Load (NFS V%d operations/second) = %d\n",
+                       nfs_version, P_total_load * Num_clients);
+    (void) fprintf(stdout, "%s%d\n",
+                   "    Maximum number of outstanding biod writes = ",
+                   P_biod_max_outstanding_writes);
+    (void) fprintf(stdout, "%s%d\n",
+                   "    Maximum number of outstanding biod reads = ",
+                   P_biod_max_outstanding_reads);
+
+    (void) fprintf(stdout, "%s%d\n%s%d\n",
+                   "    Warm-up time (seconds) = ", P_warmuptime,
+                   "    Run time (seconds) = ", Prime_runtime);
+    if (P_mix_file)
+       (void) fprintf(stdout,"%s%s\n", "    NFS Mixfile = ", P_mix_file);
+    if (P_iodist_file)
+       (void) fprintf(stdout,"%s%s\n", "    Block Size Distribution file = ",
+                       P_iodist_file);
+
+
+    (void) fprintf(stdout, "%s%6d%s\n", "    File Set = ",
+               client_stats[totals].num_io_files,
+               " Files created for I/O operations");
+    (void) fprintf(stdout, "%s%10d%s\n", "           ",
+               client_stats[totals].num_access_io_files,
+               " Files accessed for I/O operations");
+    (void) fprintf(stdout, "%s%10d%s\n", "           ",
+               client_stats[totals].num_non_io_files,
+               " Files for non-I/O operations");
+    (void) fprintf(stdout, "%s%10d%s\n", "           ",
+               client_stats[totals].num_symlinks,
+               " Symlinks");
+    (void) fprintf(stdout, "%s%10d%s\n", "           ",
+               client_stats[totals].num_dirs,
+               " Directories");
+    (void) fprintf(stdout, "%s%s\n", "           ",
+               "           Additional non-I/O files created as necessary\n");
+
+
+    (void) fprintf(stdout,"SFS Aggregate Results for %d Client(s), %s\n",
+                   Num_clients, lad_timestamp());
+    (void) fprintf(stderr, "SPEC SFS Benchmark Version %s, Creation - %s\n",
+                                SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fprintf(stdout, "NFS Protocol Version %d\n", nfs_version);
+
+    /* print column headers for per operation statistics */
+    (void) fprintf(stdout,
+"------------------------------------------------------------------------------");
+(void) fprintf(stdout, "\n");
+(void) fprintf(stdout,"%s\n%s\n%s\n%s\n%s\n",
+"NFS         Target Actual     NFS    NFS    Mean    Std Dev  Std Error   Pcnt ",
+"Op           NFS    NFS       Op     Op    Response Response of Mean,95%  of  ",
+"Type         Mix    Mix     Success Error   Time     Time    Confidence  Total",
+"             Pcnt   Pcnt     Count  Count  Msec/Op  Msec/Op  +- Msec/Op  Time ",
+"------------------------------------------------------------------------------");
+    (void) fflush(stdout);
+
+    /* print per operation statistics */
+    for (k = 0; k < NOPS; k++) {
+       tot_got = 0;
+       tot_secs = 0;
+       tot_msec_calls = 0;
+       tot_res_time =  0;
+       tot_want = 0;
+       tot_calls = 0;
+       tot_errors = 0;
+       tot_sum2_msec = 0;
+       tot_squared_time_msec = 0;
+
+       /* total the results from each client */
+       for (i = 0; i < Num_clients; i++) {
+
+           tot_want += client_stats[i].op_stats[k].want;
+           tot_got += client_stats[i].op_stats[k].got;
+           tot_calls += client_stats[i].op_stats[k].calls;
+           tot_errors += client_stats[i].op_stats[k].errors;
+           tot_secs += client_stats[i].op_stats[k].secs;
+           tot_msec_calls += client_stats[i].op_stats[k].msec_calls;
+           tot_res_time += client_stats[i].op_stats[k].res_time;
+           tot_squared_time_msec +=
+                       client_stats[i].op_stats[k].squared_time_msec;
+           tot_sum2_msec += client_stats[i].op_stats[k].sum2_msec;
+
+       } /* end for each client */
+
+       /*
+        * If the total wanted is zero and no operations succeeded or
+        * errored don't print out the
+        * summary.  However leave it in the individual client logs
+        * in case there is some interesting error.
+        */
+       if (tot_want == 0 && tot_calls == 0 && tot_errors == 0)
+           continue;
+
+       /* compute the standard deviation for the mean response time */
+       if (tot_calls <= 1) {
+           stdev_msec = 0;
+           var_msec = 0;
+       } else {
+           /* variance = 1/(n-1) * (sum(x^2) - 1/n * (sum(x))^2)  */
+           var_msec = (tot_squared_time_msec - (tot_sum2_msec / tot_calls)) /
+                       (tot_calls-1);
+
+           if(var_msec == 0.0) {
+               stdev_msec = 0.0;
+           } else
+               stdev_msec = sqrt(var_msec);
+       }
+
+       /* compute the confidence interval */
+       if (tot_calls > 0) {
+           sq_conf_interval_msec = DEFAULT_CHI_SQR_CI *
+                                   (stdev_msec / tot_calls);
+           if (sq_conf_interval_msec == 0.0) {
+               if (DEBUG_PARENT_GENERAL) {
+                   (void) fprintf(stderr,
+                       "Error computing confidence interval for mean\n");
+                   (void) fflush(stderr);
+               }
+               conf_interval_msec = 0.0;
+           } else
+               conf_interval_msec = sqrt(sq_conf_interval_msec);
+       } else {
+           conf_interval_msec = 0.0;
+       }
+
+       /* print the per op statistics */
+       (void) fprintf(stdout,
+           "%-12s%3d%%  %5.1f%%   %7d %5d %8.2f %8.2f  %8.2f    %5.1f%%\n",
+           Ops_name[k],                                        /* op name */
+           tot_want / Num_clients,                             /* target mix */
+           tot_got / Num_clients,                              /* actual mix */
+           tot_calls,                                          /* successes */
+           tot_errors,                                         /* errors */
+           tot_msec_calls / Num_clients,                       /* mean */
+           stdev_msec,                                         /* std dev */
+           conf_interval_msec,                                 /* conf int */
+           tot_res_time / Num_clients);                        /* % of time */
+
+    } /* end for each op */
+
+    (void) fprintf(stdout,
+"------------------------------------------------------------------------------\n");
+
+    /* check and report client INVALID RUN */
+    for (i = 0; i < Num_clients; i++) {
+       if (client_stats[i].client_invalid_flag != 0) {
+           invalid++;
+           (void) fprintf(stdout,"INVALID RUN reported for Client %d (%s).\n",
+                  i+1, Client_names[i]);
+           if (client_stats[i].client_invalid_flag >= INVALID_GOODCALLS) {
+               (void) fprintf(stdout,"INVALID RUN, %s\n",
+                       invalid_str[client_stats[i].client_invalid_flag]);
+           } else {
+               (void) fprintf(stdout,
+                        "INVALID RUN, ILLEGAL PARAMETER: Non-standard %s\n",
+                       invalid_str[client_stats[i].client_invalid_flag]);
+           }
+       }
+    }
+
+    (void) fprintf(stdout, "\n");
+    (void) fprintf(stdout,
+       "        --------------------------------------------------------\n");
+    (void) fprintf(stdout,
+       "        | SPEC SFS VERSION %6s AGGREGATE RESULTS SUMMARY    |\n",
+                                                       SFS_VERSION_NUM);
+    (void) fprintf(stdout,
+       "        --------------------------------------------------------\n");
+    (void) fprintf(stdout, "NFS V%d THROUGHPUT: ", nfs_version);
+    (void) fprintf(stdout,"%7.0f Ops/Sec   AVG. RESPONSE TIME: %7.1f Msec/Op\n",
+       client_stats[totals].sum_calls_sec,
+       client_stats[totals].sum_msec_calls / Num_clients);
+
+    (void) fprintf(stdout, "%s PROTOCOL\n", P_tcp ? "TCP" : "UDP");
+    (void) fprintf(stdout, "NFS MIXFILE:");
+    if (P_mix_file)
+       (void) fprintf(stdout,"%s\n", P_mix_file);
+    else (void)
+       (void) fprintf(stdout," [ SFS default ]\n");
+
+    (void) fprintf(stdout, "AGGREGATE REQUESTED LOAD: %d Ops/Sec \n",
+                   (Num_clients * P_total_load));
+
+    (void) fprintf(stdout,"TOTAL NFS OPERATIONS: %8d      TEST TIME: %d Sec \n",
+                   client_stats[totals].sum_calls,
+                   client_stats[totals].sum_secs / Num_clients);
+    (void) fprintf(stdout,"NUMBER OF SFS CLIENTS: %d\n", Num_clients);
+    (void) fprintf(stdout,
+               "TOTAL FILE SET SIZE CREATED: %6.1f MB\n" ,
+               client_stats[totals].total_fss_bytes/1024.0);
+    (void) fprintf(stdout,
+               "TOTAL FILE SET SIZE ACCESSED: %6.1f - %6.1f MB  (%lu%% to %lu%% of Base)\n",
+               client_stats[totals].least_fss_bytes/1024.0,
+               client_stats[totals].most_fss_bytes/1024.0,
+               (100 * client_stats[totals].least_fss_bytes) /
+                       client_stats[totals].base_fss_bytes,
+               (100 * client_stats[totals].most_fss_bytes) /
+                       client_stats[totals].base_fss_bytes);
+    (void) fprintf(stdout, "\n");
+
+    (void) fprintf(stdout,
+    "------------------------------------------------------------------------");
+    (void) fprintf(stdout,"\n\n");
+    (void) fflush(stdout);
+
+    /*
+     * Summary results file format:
+     *                 response total   elps                  prcs biod  vers
+     *  load   thruput time     ops     time V P fileset_sz clnt   rd wr
+     * DDDDDDD FFFFFFF FFFFFFF DDDDDDDD DDDD D C DDDDDDDDDD DDD DD DD DD SSSS
+     */
+    (void) fprintf(sum_result_fp,
+"%7s %7d %7.0f %7.1f %8d %4d %1d %c %10lu %3d %2d %2d %2d %s\n",
+                       invalid ? "INVALID" : "",
+                       Num_clients * P_total_load,
+                       client_stats[totals].sum_calls_sec,
+                       client_stats[totals].sum_msec_calls / Num_clients,
+                       client_stats[totals].sum_calls,
+                       client_stats[totals].sum_secs / Num_clients,
+                       nfs_version,
+                       P_tcp ? 'T' : 'U',
+                       (unsigned long)client_stats[totals].total_fss_bytes,
+                       Num_clients,
+                       P_children,
+                       P_biod_max_outstanding_reads,
+                       P_biod_max_outstanding_writes,
+                       SFS_VERSION_NUM);
+    (void) fflush(sum_result_fp);
+
+    (void) free(client_stats);
+} /* print_multi_results */
+
+static void
+prog_usage(void)
+{
+   (void) fprintf(stderr,
+      "Usage: %s [-a access_pcnt] [-A append_pcnt] [-b blocksz_file] [-B block_size]\n",
+       sfs_Myname);
+    (void) fprintf(stderr,
+      "\t[-C summary_file] [-d debug_level] [-f file_set_delta]\n");
+    (void) fprintf(stderr,
+      "\t[-k script_name] [-K script_args] [-l load] [-m mix_file]\n");
+    (void) fprintf(stderr,
+      "\t[-p procs] [-Q] [-R biod_reads] [-s sleeptime]\n");
+    (void) fprintf(stderr,
+      "\t[-t time] [-T op_num] [-w warmup] [-x timeout]\n");
+    (void) fprintf(stderr,
+      "\t[-W biod_writes] [-z] <hostname1> [<hostname2>...]\n");
+
+
+    (void) fflush(stderr);
+    (int) signal_sfs_clients("PRIME_STOP");
+    exit(64);
+    /* NOTREACHED */
+} /* prog_usage */
+
+/* sfs_m_prm.c */
diff --git a/TBBT/trace_play/sfs_m_snc.c b/TBBT/trace_play/sfs_m_snc.c
new file mode 100644 (file)
index 0000000..8a8f2e2
--- /dev/null
@@ -0,0 +1,456 @@
+#ifndef lint
+static char sccsid[] = "@(#)sfs_m_snc.c        2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *.Exported_routines
+ *     None.
+ *
+ *.Local_routines
+ *     void sfs_syncprog_1(struct svc_req *, SVCXPRT *)
+ *     int * signal_sync_sfs_1(struct sync_string *)
+ *     void lad_syncd_cleanup(int)
+ *
+ *.Revision_history
+ *      04-Dec-91      Keith   Include sfs_def.h for SYSV/SVR4 mem*
+ *                             functions. Include string.h for SYSV/SVR4.
+ *     28-Nov-91       Teeluckingh     Fixed 'multiple signals to sfs'
+ *                             problem.  Uses a 'transaction id' field in
+ *                             the sync rpc xdr structure to compare
+ *                             previous rpc, if the current transaction id
+ *                             matches the previous one then sfs_syncd
+ *                             just return 'success' to the client. If the
+ *                             transaction ids do not match, the actions
+ *                             are performed and the transaction id value
+ *                             is saved.
+ *     17-Jun-91       Teelucksingh    Creation - multi-client
+ *                             synchronization server sfs_syncd.
+ *                             Processes the sfs sync rpcs between systems.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <sys/signal.h>
+#include <sys/file.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+
+/* forward definitions for local routines */
+static void sfs_syncprog_1(struct svc_req *, SVCXPRT *);
+static int * signal_sync_sfs_1(struct sync_string *);
+static void lad_syncd_cleanup(int);
+
+/*
+ * -----------------------  Static Definitions  -----------------------
+ */
+
+int Debug_level = 0;            /* flag indicates prime client debug mode */
+char *sfs_Myname;                   /* program name */
+
+static char previous_transaction[MAX_STR1_LEN];        /* to hold transaction id */
+
+
+/*
+ * -------------------  Multi-client Synchronization  -------------------
+ */
+
+
+/*ARGSUSED*/
+int
+main(
+    int                argc,
+    char *     argv[])
+{
+    char       *nameptr;
+    SVCXPRT *  transp;
+    FILE       *pid_fp;
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    struct sigaction sig_act, old_sig_act;
+#endif /* USE_POSIX_SIGNALS */
+
+    /* 
+     * Place pid in pid log file 
+     */   
+    if ((pid_fp = fopen(SFS_SYNCD_PID, "a+")) == NULL) { 
+        perror(SFS_SYNCD_PID);  
+        (void) unlink(SFS_SYNCD_PID); 
+        exit(1); 
+    } 
+    (void) fprintf(pid_fp, "%d\n", getpid()); 
+    (void) fclose(pid_fp);
+
+    sfs_Myname = argv[0];
+
+    if ((nameptr = strrchr(argv[0], '/')) != NULL)
+        sfs_Myname = ++nameptr;
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    /* use XOPEN signal handling */
+    sig_act.sa_handler = generic_catcher;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+
+    /* signals handlers for signals used by sfs_prime */
+    sig_act.sa_handler = lad_syncd_cleanup;
+    if (sigaction(SIGINT,&sig_act,&old_sig_act) != 0) {
+               perror("sigaction failed: SIGINT");
+               (void) unlink(SFS_SYNCD_PID); 
+               exit(4);
+    }
+#else
+    /* set up SIGINT signal handler */
+    (void) signal(SIGINT, lad_syncd_cleanup);
+#endif /* USE_POSIX_SIGNALS */
+
+    (void) fprintf(stderr,"--------------------\n");
+    (void) fprintf(stderr,"Start of sfs run.\n");
+
+    (void) pmap_unset(SFS_SYNCPROG, SFS_SYNCVERS);
+
+    transp = svcudp_create(RPC_ANYSOCK);
+    if (transp == ((SVCXPRT *) NULL)) {
+       (void) fprintf(stderr, "%s: cannot create udp service.\n", sfs_Myname);
+               (void) unlink(SFS_SYNCD_PID); 
+       exit(5);
+    }
+    if (!svc_register(transp, SFS_SYNCPROG, SFS_SYNCVERS,
+                    sfs_syncprog_1, IPPROTO_UDP)) {
+       (void) fprintf(stderr,
+           "%s: unable to register (SFS_SYNCPROG,SFS_SYNCVERS, udp).\n",
+           sfs_Myname);
+               (void) unlink(SFS_SYNCD_PID); 
+       exit(6);
+    }
+
+    transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+    if (transp == ((SVCXPRT *) NULL)) {
+       (void) fprintf(stderr, "%s: cannot create tcp service.\n", sfs_Myname);
+               (void) unlink(SFS_SYNCD_PID); 
+       exit(6);
+    }
+    if (!svc_register(transp, SFS_SYNCPROG, SFS_SYNCVERS,
+                     sfs_syncprog_1, IPPROTO_TCP)) {
+       (void) fprintf(stderr,
+           "%s: unable to register (SFS_SYNCPROG, SFS_SYNCVERS, tcp).\n",
+           sfs_Myname);
+               (void) unlink(SFS_SYNCD_PID); 
+       exit(7);
+    }
+
+    svc_run();
+    (void) fprintf(stderr, "%s: svc_run returned\n", sfs_Myname);
+    return(1);
+
+} /* main */
+
+
+static void
+sfs_syncprog_1(
+    struct svc_req *   rqstp,
+    SVCXPRT *          transp)
+{
+    union {
+       sync_string     signal_sync_sfs_1_arg;
+    } argument;
+    char *             result;
+    bool_t             (*xdr_argument)(), (*xdr_result)();
+    char *             (*local)();
+
+    switch (rqstp->rq_proc) {
+       case SIGNAL_NULLPROC:
+           (void) svc_sendreply(transp, xdr_void, (char *)NULL);
+           return;
+
+       case SIGNAL_SFS:
+           xdr_argument = xdr_sync_string;
+           xdr_result = xdr_int;
+           local = (char * (*)()) signal_sync_sfs_1;
+           break;
+
+       default:
+           svcerr_noproc(transp);
+           return;
+    }
+    (void) memset((char *) &argument, '\0', sizeof(argument));
+    if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
+       svcerr_decode(transp);
+       return;
+    }
+    result = (*local)(&argument);
+    if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+       svcerr_systemerr(transp);
+    }
+    if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
+       (void) fprintf(stderr, "%s: unable to free arguments\n", sfs_Myname);
+               (void) unlink(SFS_SYNCD_PID); 
+       exit(8);
+    }
+
+} /* sfs_syncprog_1 */
+
+
+/*
+ * signal_sync_sfs_1 - multi-client synch RPC
+ * Provides interface between sfs program running
+ * on multiple clients and the controlling sfs_prime program.
+ */
+static int *
+signal_sync_sfs_1(
+    struct sync_string *       sfs_signal)
+{
+    static int                 result = 0 ;    /* return status - failure */
+    FILE *                     fp;
+    int                                sfs_pid;        /* sfs parent process pid */
+    char                       datafile[SFS_MAXPATHLEN]; /* results file */
+    char                       CL_Logname[SFS_MAXPATHLEN];
+
+    result = 0;
+    /* if a duplicate transactions then just return success to calling client */
+    if (strcmp(sfs_signal->clnt_transaction, previous_transaction) == 0) {
+       (void) fprintf(stderr,"%s: Got a duplicate signal - %s\n",
+                       sfs_Myname, sfs_signal->clnt_transaction);
+       result = 1;
+       return(&result);
+    }
+
+    if (strcmp(sfs_signal->clnt_type,"CLIENT_SIGNAL") == 0) {
+
+       /*
+        * message from parent sfs process on client to Prime-client
+        * (sfs_prime).
+        *
+        * Append client id to Prime client sync logfile
+        */
+       fp = fopen(SFS_PRIME_SYNC_LOG, "a");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, SFS_PRIME_SYNC_LOG);
+           return (&result);
+       }
+       (void) fwrite((char *)&sfs_signal->clnt_id,
+                       sizeof(sfs_signal->clnt_id), 1, fp);
+       (void) fclose(fp);
+       result = 1;
+       (void) sprintf(previous_transaction, sfs_signal->clnt_transaction);
+       (void) fprintf(stderr,"%s: Got Client_SIGNAL - %s\n",
+                       sfs_Myname, sfs_signal->clnt_transaction);
+       return (&result); /* success */
+
+    } else if (strcmp(sfs_signal->clnt_type,"CLIENT_DATA") == 0) {
+
+       /*
+        * message from parent sfs process on client to Prime-client
+        * completed run, here are my results. Write it to file and let
+        * Prime client know about it.
+        */
+       (void) sprintf(datafile,"%s%d",
+                       PRIME_RESULTS_LOG, sfs_signal->clnt_id);
+       fp = fopen(datafile, "w");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, datafile);
+           return (&result);
+       }
+       (void) fprintf(fp,"%s",sfs_signal->clnt_data);
+       (void) fclose(fp);
+
+       /* after writing data write client id to sync log */
+       fp = fopen(SFS_PRIME_SYNC_LOG, "a");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, SFS_PRIME_SYNC_LOG);
+           return (&result);
+       }
+       (void) fwrite((char *)&sfs_signal->clnt_id,
+                               sizeof(sfs_signal->clnt_id), 1, fp);
+       (void) fclose(fp);
+
+       /* let the remote process know success */
+       result = 1;
+       (void) sprintf(previous_transaction, sfs_signal->clnt_transaction);
+       (void) fprintf(stderr,"%s: Got Client_DATA - %s\n",
+                       sfs_Myname, sfs_signal->clnt_transaction);
+       return (&result);
+
+    } else if (strcmp(sfs_signal->clnt_type,"CLIENT_STOP") == 0) {
+
+       /*
+        * message from parent sfs process on client to Prime-client
+        * (sfs_prime) to stop due to error.
+        */
+       fp = fopen(SFS_PRIME_SYNC_LOG, "a");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, SFS_PRIME_SYNC_LOG);
+           return (&result);
+       }
+       /*
+        * Write out client id 1000 times to fool prime into thinking
+        * all clients have responded and will get an error when it
+        * tries to communicate to it.
+        */
+       for (result = 0; result < 1000; result++)
+               (void) fwrite((char *)&sfs_signal->clnt_id,
+                       sizeof(sfs_signal->clnt_id), 1, fp);
+       (void) fclose(fp);
+       result = 1;
+       (void) sprintf(previous_transaction, sfs_signal->clnt_transaction);
+       (void) fprintf(stderr,"%s: Got Client_STOP - %s\n",
+                       sfs_Myname, sfs_signal->clnt_transaction);
+       return (&result); /* success */
+
+    } else if (strcmp(sfs_signal->clnt_type,"PRIME_SIGNAL") == 0) {
+
+       /*
+        * message from the Prime client (sfs_prime)
+        * send SIGUSR1 signal to parent sfs process on
+        * client - signals it to proceed
+        */
+       (void) sprintf(CL_Logname,"%s%d",
+                       SFS_CLIENT_SYNC_LOG, sfs_signal->clnt_id);
+       fp = fopen(CL_Logname, "r");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, CL_Logname);
+           return(&result);
+       }
+       if (fscanf(fp,"%d",&sfs_pid) != 1)
+           return (&result);
+       if ((int) generic_kill(sfs_pid, SIGUSR1) == 0) {
+           result = 1;
+           (void) sprintf(previous_transaction,
+                          sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"%s: Got PRIME_SIGNAL(SIGUSR1) - %s\n",
+                           sfs_Myname, sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"   Sent SIGUSR1\n");
+           return (&result); /* success */
+       } else
+           return (&result);
+
+    } else if (strcmp(sfs_signal->clnt_type,"PRIME_ALARM") == 0) {
+
+       /*
+        * message from the Prime client (sfs_prime)
+        * send SIGALRM signal to parent sfs process on
+        * client - tell it to wake up and finish execution at this time
+        */
+
+       (void) sprintf(CL_Logname,"%s%d",
+                       SFS_CLIENT_SYNC_LOG, sfs_signal->clnt_id);
+       fp = fopen(CL_Logname, "r");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, CL_Logname);
+           return (&result);
+       }
+       if (fscanf(fp,"%d",&sfs_pid) != 1)
+           return (&result);
+       if ((int) generic_kill(sfs_pid, SIGALRM) == 0) {
+           result = 1;
+           (void) sprintf(previous_transaction,
+                          sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"%s: Got PRIME_ALARM(SIGALRM) - %s\n",
+                               sfs_Myname, sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"   Sent SIGALRM\n");
+           return (&result); /* success */
+       } else
+           return (&result);
+
+    } else if (strcmp(sfs_signal->clnt_type,"PRIME_STOP") == 0) {
+
+       /*
+        * message from Prime-client
+        * sent SIGINT signal to sfs parent process
+        * to tell it to terminate experiment now
+        */
+       (void) sprintf(CL_Logname,"%s%d",
+                       SFS_CLIENT_SYNC_LOG, sfs_signal->clnt_id);
+       fp = fopen(CL_Logname, "r");
+       if (fp == NULL) {
+           (void) fprintf(stderr,"%s: Cannot open %s\n",
+               sfs_Myname, CL_Logname);
+           return (&result);
+       }
+       if (fscanf(fp,"%d",&sfs_pid) != 1)
+           return (&result);
+       if ((int) generic_kill(sfs_pid, SIGINT) == 0) {
+           result = 1;
+           (void) sprintf(previous_transaction,
+                          sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"%s: Got PRIME_STOP(SIGSTOP) - %s\n",
+                               sfs_Myname, sfs_signal->clnt_transaction);
+           (void) fprintf(stderr,"   Sent SIGINT\n");
+           return (&result); /* success */
+       } else
+           return (&result);
+
+    } else
+       return (&result); /* failure */
+
+} /* signal_sync_sfs_1 */
+
+/* ARGSUSED */
+static void
+lad_syncd_cleanup(
+    int         sig_id)
+{
+    (void) pmap_unset(SFS_SYNCPROG, SFS_SYNCVERS);
+    (void) fprintf(stderr, "Unregistered sfs_syncd.\n");
+    (void) unlink(SFS_SYNCD_PID); 
+    exit(0);
+
+} /* lad_syncd_cleanup */
+
+/* sfs_m_snc.c */
diff --git a/TBBT/trace_play/sfs_m_xdr.c b/TBBT/trace_play/sfs_m_xdr.c
new file mode 100644 (file)
index 0000000..b2cf930
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef lint
+static char sfs_m_xdrSid[] = "@(#)sfs_m_xdr.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *.Exported_routines
+ *     bool_t xdr_sync_string(XDR *, sync_string *)
+ *
+ *.Revision_history
+ *     28-Nov-91       0.0.13  Teelucksingh
+ *                             added 'transaction id' field to xdr data
+ *                             structure and ANSI C features.
+ *     17-Jun-91       0.0.7   Teelucksingh - Creation
+ *                             Multi-client synchronization rpc xdr
+ *                             functions.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+/*
+ * ---------------  Multi-client Message XDR Routines  ---------------
+ */
+
+bool_t
+xdr_sync_string(
+    XDR *              xdrs,
+    sync_string *      objp)
+{
+    if (!xdr_int(xdrs, (int *) &objp->clnt_id)) {
+       (void) fprintf(stderr, "%s: can't encode client id %d",
+                       sfs_Myname, objp->clnt_id);
+       return (FALSE);
+    }
+    if (!xdr_string(xdrs, (char **) &objp->clnt_type,
+                                       (unsigned int) MAX_STR1_LEN)) {
+       (void) fprintf(stderr, "%s: can't encode client type %s",
+                       sfs_Myname, objp->clnt_type);
+       return (FALSE);
+    }
+    if (!xdr_string(xdrs, (char **) &objp->clnt_transaction,
+                                       (unsigned int) MAX_STR1_LEN)) {
+       (void) fprintf(stderr, "%s: can't encode client transaction %s",
+                       sfs_Myname, objp->clnt_transaction);
+       return (FALSE);
+    }
+    if (!xdr_string(xdrs, (char **) &objp->clnt_data,
+                                       (unsigned int) MAX_STR2_LEN)) {
+       (void) fprintf(stderr, "%s: can't encode client data %s",
+                       sfs_Myname, objp->clnt_data);
+       return (FALSE);
+    }
+    return (TRUE);
+}
+
+
+/* sfs_m_xdr.c */
diff --git a/TBBT/trace_play/sfs_mcr b/TBBT/trace_play/sfs_mcr
new file mode 100755 (executable)
index 0000000..c24fb3e
--- /dev/null
@@ -0,0 +1,170 @@
+#! /bin/sh
+#      @(#)sfs_mcr     2.1     97/10/23
+#
+#
+#    Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+#      All rights reserved.
+#              Standard Performance Evaluation Corporation (SPEC)
+#              6585 Merchant Place, Suite 100
+#              Warrenton, VA 20187
+#      This product contains benchmarks acquired from several sources who
+#      understand and agree with SPEC's goal of creating fair and objective
+#      benchmarks to measure computer performance.
+#
+#      This copyright notice is placed here only to protect SPEC in the
+#      event the source is misused in any manner that is contrary to the
+#      spirit, the goals and the intent of SPEC.
+#
+#      The source code is provided to the user or company under the license
+#      agreement for the SPEC Benchmark Suite for this product.
+#
+# *****************************************************************
+# *                                                               *
+# *    Copyright 1991,1992  Legato Systems, Inc.                 *
+# *    Copyright 1991,1992  Auspex Systems, Inc.                 *
+# *    Copyright 1991,1992  Data General Corporation             *
+# *    Copyright 1991,1992  Digital Equipment Corporation        *
+# *    Copyright 1991,1992  Interphase Corporation               *
+# *    Copyright 1991,1992  Sun Microsystems, Inc.               *
+# *                                                               *
+# *****************************************************************
+#
+# Usage sfs_mcr <sfs parameter string>
+#
+# Teelucksingh - Creation (6/17/91)
+#
+# This script is remotely started from the Prime-client
+# by sfs_mgr .
+#
+
+#
+# Client pid files
+#
+SFS_PNT_PID="/tmp/sfs_pnt_pid"
+SFS_SYNCD_PID="/tmp/sfs_syncd_pid"
+
+# SFS client log files
+CLIENT_LOG_FILES="/tmp/sfs_CL$CLIENT_NUM \
+               /tmp/sfs_sig$CLIENT_NUM \
+               /tmp/sfs_x$CLIENT_NUM"
+
+if [ "$1" = "cleanup" ]; then
+    #
+    # do cleanup
+    #
+    rm -f $CLIENT_LOG_FILES
+
+    #
+    # clean up any 'old' sfs processes
+    #
+    if [ -f $SFS_PNT_PID ]; then
+        kill -2 `cat $SFS_PNT_PID` > /dev/null 2>&1
+        rm -f $SFS_PNT_PID
+    fi
+    if [ -f $SFS_SYNCD_PID ]; then
+        kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+        rm -f $SFS_SYNCD_PID
+    fi
+
+    exit
+fi
+
+# read command line arguments
+SFS_PROG=$1
+shift
+SFS_DIR=$1
+shift
+S_LOGFILE=$1
+shift
+C_LOGFILE=$1
+shift
+CLIENT_NUM=$1
+shift
+
+# print start message
+echo "========================================================================" >> $C_LOGFILE
+echo "" >> $C_LOGFILE
+
+#
+# decide whether to use BSD (which one) or SYSV variant of commands
+#
+# do test to see whether to use hostname or uname
+sh -c "hostname > /dev/null 2>&1" > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+       HOSTNAME_CMD="hostname"
+else
+       sh -c "uname -n  > /dev/null 2>&1" > /dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               HOSTNAME_CMD="uname -n"
+       else
+        echo "sfs_mcr: can't use hostname(1) or uname(1), exiting." >> $C_LOGFILE
+               exit 1
+       fi
+fi
+
+#
+# trap for signals used by sfs
+#
+# Try to find cpp in the common places, if not there then let PATH find it
+if [ "$CPP" = "" ]
+then
+    if [ -f /lib/cpp ]
+    then
+        CPP=/lib/cpp
+    elif [ -f /usr/ccs/lib/cpp ]
+    then
+        CPP=/usr/ccs/lib/cpp
+    else
+        CPP=cpp
+    fi
+fi
+
+#
+# Allow trap numbers to be defined externally for broken systems
+#
+if [ "$TRAP_NUMS" = "" ]
+then
+    echo "#include <signal.h>" > /tmp/sfs_sig$CLIENT_NUM
+    echo "myprint SIGINT SIGALRM SIGTERM SIGUSR1 SIGUSR2" >> \
+         /tmp/sfs_sig$CLIENT_NUM
+    cat /tmp/sfs_sig$CLIENT_NUM | $CPP | grep myprint | \
+        awk '{print $2 " " $3 " " $4 " " $5 " " $6}'  > /tmp/sfs_x$CLIENT_NUM
+    TRAP_NUMS=`cat /tmp/sfs_x$CLIENT_NUM`
+fi
+trap "" $TRAP_NUMS
+
+#
+# start the sync daemon on the client
+#
+# Let's truncate the syncd log file at the start of each invocation
+# of sfs_mcr. Else it grows unbounded.
+#
+trap "" $TRAP_NUMS
+$SFS_DIR/sfs_syncd > $S_LOGFILE 2>&1 &
+echo "Started: sfs_syncd on client (`$HOSTNAME_CMD`). " >> $C_LOGFILE
+
+#
+# start SFS
+trap "" $TRAP_NUMS
+echo "Starting: $SFS_DIR/$SFS_PROG -N $CLIENT_NUM $*" >> $C_LOGFILE
+
+$SFS_DIR/$SFS_PROG -N $CLIENT_NUM $*  >> $C_LOGFILE 2>&1
+
+if [ $? -ne 0 ]; then     # error condition
+   # clean up
+   echo "sfs_mcr: sfs benchmark terminated with error status" >>$C_LOGFILE
+fi
+
+#
+# clean up any 'old' sfs processes
+#
+if [ -f $SFS_PNT_PID ]; then
+    kill -2 `cat $SFS_PNT_PID` > /dev/null 2>&1
+    rm -f $SFS_PNT_PID
+fi
+if [ -f $SFS_SYNCD_PID ]; then
+    kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+    rm -f $SFS_SYNCD_PID
+fi
+
+trap $TRAP_NUMS
diff --git a/TBBT/trace_play/sfs_mgr b/TBBT/trace_play/sfs_mgr
new file mode 100755 (executable)
index 0000000..c1203a4
--- /dev/null
@@ -0,0 +1,1093 @@
+#! /bin/sh
+#       @(#)sfs_mgr  2.1     97/10/23
+#
+#    Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+#      All rights reserved.
+#              Standard Performance Evaluation Corporation (SPEC)
+#              6585 Merchant Palce, Suite 100
+#              Warrenton, VA 20187
+#      This product contains benchmarks acquired from several sources who
+#      understand and agree with SPEC's goal of creating fair and objective
+#      benchmarks to measure computer performance.
+#
+#      This copyright notice is placed here only to protect SPEC in the
+#      event the source is misused in any manner that is contrary to the
+#      spirit, the goals and the intent of SPEC.
+#
+#      The source code is provided to the user or company under the license
+#      agreement for the SPEC Benchmark Suite for this product.
+#
+# *****************************************************************
+# *                                                               *
+# *    Copyright 1991,1992  Legato Systems, Inc.                 *
+# *    Copyright 1991,1992  Auspex Systems, Inc.                 *
+# *    Copyright 1991,1992  Data General Corporation             *
+# *    Copyright 1991,1992  Digital Equipment Corporation        *
+# *    Copyright 1991,1992  Interphase Corporation               *
+# *    Copyright 1991,1992  Sun Microsystems, Inc.               *
+# *                                                               *
+# *****************************************************************
+#
+# Usage sfs_mgr [-r <rc file>] [-s <suffix>] [-v <level>]
+#
+# Teelucksingh - Creation (6/17/91)
+#
+# Starts SFS (sfs_mcr) on clients with parameters
+# specified in sfs_rc .
+# Starts Prime-client program (sfs_prime)
+# Can have multiple runs with incrementing load
+# Summarized result(s) placed in sfsres.<suffix>
+# Log of multi-client run placed in sfslog.<suffix>
+# Individual client result(s) placed in sfs<cnnn>.<suffix>
+#
+#
+
+# --------------- defined constants and strings --------------
+#
+
+STARline='************************************************************************'
+RHOSTSCKMSG1="Ensure permissions in .rhosts or hosts.equiv allows remote operation."
+RHOSTSCKMSG2="Or check target directory/file existence or permissions."
+USAGE="usage: $0 [-r <rc file>] [-s <suffix>] [-v <level>]"
+
+# ----------------- variable initialization ------------------
+#
+
+error=FALSE
+
+# --------------- program initialization phase ---------------
+#
+# get the command line arguments
+#
+# init with default
+#
+SUFFIX=out
+RC_FILE=./sfs_rc
+VALIDATE=0
+#
+if [ $# -gt 6 ]
+then
+    echo $USAGE
+    exit 1
+fi
+while [ $# -gt 0 ]
+do
+    if [ "$#" -lt 2 ]
+    then
+        echo $USAGE
+       exit 1
+    fi
+    case $1 in
+    -r)
+           RC_FILE=$2
+           ;;
+    -s)
+           SUFFIX=$2
+           ;;
+    -v)
+           VALID_LEVEL=$2
+           VALIDATE=1
+           ;;
+    *)     echo $USAGE
+           exit 1
+    esac
+    shift; shift
+done
+
+#
+# pass in environment variables from sfs_rc
+#
+if [ ! -r "$RC_FILE" ]; then
+    echo "sfs_mgr: missing or protected rc file $RC_FILE"
+    exit 1
+fi
+. "$RC_FILE"
+
+#
+# Make sure WORK_DIR is defined
+#
+if [ "$WORK_DIR" = "" ]
+then
+    echo "sfs_mgr: WORK_DIR not defined, check sfs_rc file, exiting."
+    exit 1
+fi
+
+#
+# Prime client output files
+#
+P_OUTFILE=$WORK_DIR/sfsres.$SUFFIX
+P_SUMFILE=$WORK_DIR/sfssum.$SUFFIX
+P_LOGFILE=$WORK_DIR/sfslog.$SUFFIX
+P_VALFILE=$WORK_DIR/sfsval.$SUFFIX
+
+#
+# Client pid files
+#
+SFS_PNT_PID="/tmp/sfs_pnt_pid"
+SFS_PRM_PID="/tmp/sfs_prm_pid"
+SFS_SYNCD_PID="/tmp/sfs_syncd_pid"
+
+#
+# --------------------
+# Setup machine/OS dependant parameters
+#
+# decide whether to use BSD (which one) or SYSV variant of commands
+#
+# do echo test to get no end-of-line character
+#
+op=`echo "\c"`
+if [ "$op" = "\c" ]; then
+    ECHO_NONL="echo -n"
+    NONL=
+else
+    ECHO_NONL="echo"
+    NONL="\c"
+fi
+
+#
+# do test to see whether to use hostname or uname
+#
+if sh -c "hostname > /dev/null 2>&1"  > /dev/null 2>&1
+then
+    HOSTNAME_VAL=`hostname`
+elif sh -c "uname -n  > /dev/null 2>&1" > /dev/null 2>&1
+then
+    HOSTNAME_VAL=`uname -n`
+else
+    echo "sfs_mgr: can't use hostname(1) or uname(1), exiting."
+    echo "sfs_mgr: can't use hostname(1) or uname(1), exiting." \
+                >> $P_LOGFILE
+    exit 1
+fi
+
+#
+# Make sure RSH is defined, if not set reasonable default
+# RSH_CMD overrides RSH if set
+#
+if [ "$RSH_CMD" != "" ]
+then
+    RSH=$RSH_CMD
+fi
+    
+if [ "$RSH" = "" ]
+then
+    RSH="rsh"
+fi
+
+#
+# If CPP is not already defined then
+# try to find cpp in the common places, if not there then let PATH find it
+#
+if [ "$CPP" = "" ]; then
+    if [ -f /lib/cpp ]
+    then
+        CPP=/lib/cpp
+    elif [ -f /usr/ccs/lib/cpp ]
+    then
+        CPP=/usr/ccs/lib/cpp
+    else
+        CPP=cpp
+    fi
+fi
+
+#
+# trap for signals used by sfs programs
+#
+if [ "$TRAP_NUMS" = "" ]
+then
+    echo "#include <signal.h>" > /tmp/sfs_tmp1
+    echo "myprint SIGINT SIGALRM SIGTERM SIGUSR1 SIGUSR2" >> /tmp/sfs_tmp1
+    cat /tmp/sfs_tmp1 | $CPP | grep myprint | \
+        awk '{print $2 " " $3 " " $4 " " $5 " " $6}' > /tmp/sfs_tmp2
+    TRAP_NUMS=`cat /tmp/sfs_tmp2`
+fi
+rm -f /tmp/sfs_tmp1 /tmp/sfs_tmp2
+#
+# --------------------
+
+#
+# Get NFS version number
+#
+SFS_PROG="sfs"
+if [ "$NFS_VERSION" != "" ]
+then
+    if [ "$NFS_VERSION" = "3" ]
+    then
+       SFS_PROG="sfs3"
+    elif [ "$NFS_VERSION" != "2" ]
+    then
+       echo "sfs_mgr: Illegal NFS version number: $NFS_VERSION" \
+                       >> $P_LOGFILE 2>&1
+       echo "sfs_mgr: Illegal NFS version number: $NFS_VERSION"
+       exit 1
+    fi
+fi
+
+#
+# print logfile header information
+#
+echo '========================================================================'\
+       >>$P_LOGFILE
+echo " " >>$P_LOGFILE
+echo "SFS NFS Benchmark Prime Client Logfile." >>$P_LOGFILE
+echo "        Creation Date: `date`" >>$P_LOGFILE
+echo "        Prime Client hostname: $HOSTNAME_VAL" >>$P_LOGFILE
+
+#
+# check for mixfile and block-size file
+# if specified
+#
+# check for mixfile
+#
+if [ "$MIXFILE" != "" -a ! -r "$WORK_DIR/$MIXFILE" ]
+then
+    echo "sfs_mgr: error missing or protected mixfile $WORK_DIR/$MIXFILE" \
+               >> $P_LOGFILE 2>&1
+    echo "sfs_mgr: error missing or protected mixfile $WORK_DIR/$MIXFILE"
+    exit 1
+fi
+
+#
+# check for block size file
+#
+if [ "$BLOCK_FILE" != "" -a ! -r "$WORK_DIR/$BLOCK_FILE" ]
+then
+    echo "sfs_mgr: error missing or protected block size file \
+           $WORK_DIR/$BLOCK_FILE" >> $P_LOGFILE 2>&1
+    echo "sfs_mgr: error missing or protected block size file \
+           $WORK_DIR/$BLOCK_FILE"
+    exit 1
+fi
+
+#
+#
+NUM_CLIENTS=0
+PRIME_CLIENT_NUM=0
+for i in $CLIENTS; do
+    NUM_CLIENTS=`expr $NUM_CLIENTS + 1`
+    #
+    # hack: First try a simple remote "echo" to
+    # /dev/null. If the $RSH fails, then we don't have
+    # permission to execute the remote command sfs_mcr.
+    # The initial probe is necessary because we must
+    # background the sfs_mcr rsh because we're looping
+    # on all clients, and spawn a bunch, and the rsh won't
+    # detach from the command. So, the probe.
+    #
+    $RSH $i -l $SFS_USER "echo >/dev/null" >/dev/null 2>&1 </dev/null
+    if [ $? -ne 0 ]; then
+       echo "sfs_mgr: test rsh to $i failed"
+       echo "            $RHOSTSCKMSG1"
+       echo "sfs_mgr: test rsh to $i failed" >> $P_LOGFILE
+       echo "            $RHOSTSCKMSG1" >> $P_LOGFILE
+       exit 1
+    fi
+
+    # Get canonical hostname of client $i and see if it is the prime client.
+    client_name=`$RSH $i -l $SFS_USER 'hostname || uname -n' 2>/dev/null </dev/null`
+    if [ "$client_name" = $HOSTNAME_VAL ]
+    then
+       PRIME_CLIENT_NUM=$NUM_CLIENTS
+       continue
+    fi
+    #
+    # Also check to make sure the work directory exists
+    #
+    exists=`$RSH $i -l $SFS_USER sh -c \"if [ -d $WORK_DIR ]\; then echo 0 \; else echo 1 \; fi\" </dev/null`
+    if [ "$exists" != 0 ]; then
+       echo "sfs_mgr: $WORK_DIR on $i does not exist"
+       echo "sfs_mgr: $WORK_DIR on $i does not exist" >> $P_LOGFILE
+       exit 1
+    fi
+    #
+    # propagate the mixfile to remote clients
+    #
+    if [ "$MIXFILE" != "" ]; then
+       rcp "$WORK_DIR/$MIXFILE" \
+          "$SFS_USER"@"$i":"$WORK_DIR/$MIXFILE" >> $P_LOGFILE 2>&1
+       if [ $? -ne 0 ]; then
+           echo \
+           "sfs_mgr: can't rcp mix file $WORK_DIR/$MIXFILE to client $i."
+           echo "            $RHOSTSCKMSG1"
+           echo "            $RHOSTSCKMSG2"
+           echo \
+           "sfs_mgr: can't rcp mix file $WORK_DIR/$MIXFILE to client $i." \
+                       >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG1" >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG2" >> $P_LOGFILE
+           exit 1
+       fi
+    fi
+    #
+    # propagate block size file to remote clients
+    #
+    if [ "$BLOCK_FILE" != "" ]; then
+       rcp "$WORK_DIR/$BLOCK_FILE" \
+               "$SFS_USER"@"$i":"$WORK_DIR/$BLOCK_FILE" >> $P_LOGFILE 2>&1
+       if [ $? -ne 0 ]; then
+           echo \
+    "sfs_mgr: can't rcp block size file $WORK_DIR/$BLOCK_FILE to client $i."
+           echo "            $RHOSTSCKMSG1"
+           echo "            $RHOSTSCKMSG2"
+           echo \
+    "sfs_mgr: can't rcp block size file $WORK_DIR/$BLOCK_FILE to client $i." \
+                       >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG1"    >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG2"    >> $P_LOGFILE
+           exit 1
+       fi
+    fi
+done
+
+if [ "$NUM_CLIENTS" -eq 0 ]; then
+    echo "Cannot run SFS with no clients."
+    echo "Assign value to CLIENT variable in sfs_rc."
+    echo "Cannot run SFS with no clients."     >> $P_LOGFILE
+    echo "Assign value to CLIENT variable in sfs_rc."  >> $P_LOGFILE
+    exit 1
+fi
+
+
+echo "        Number of Clients: $NUM_CLIENTS" >>$P_LOGFILE
+echo "        Client hostname(s): $CLIENTS" >>$P_LOGFILE
+echo " " >>$P_LOGFILE
+
+#
+# Loop invariant setup
+# -------------------
+#
+# check for program that starts external monitoring
+#
+if [ "$PRIME_MON_SCRIPT" != "" -a ! -x "$WORK_DIR/$PRIME_MON_SCRIPT" ]
+then
+    echo "sfs_mgr: error missing or not executeable program \
+       $WORK_DIR/$PRIME_MON_SCRIPT" >> $P_LOGFILE 2>&1
+    echo "sfs_mgr: error missing or not executeable program \
+           $WORK_DIR/$PRIME_MON_SCRIPT"
+    exit 1
+fi
+
+#
+# Set default number of procs if missing
+#
+PRCS=$PROCS
+if [ "$PRCS" = "" ]; then
+    PRCS=4
+fi
+
+if [ "$MNT_POINTS" = "" ]; then
+    echo "sfs_mgr: MNT_POINTS not specified" >> $P_LOGFILE 2>&1
+    echo "sfs_mgr: MNT_POINTS not specified"
+    exit 1
+fi
+
+set `echo $MNT_POINTS`
+NUM_MNTS=$#
+MPC=`expr $NUM_CLIENTS \* $PRCS`
+if [ $NUM_MNTS -ne 1 -a $NUM_MNTS -ne $PRCS -a  $NUM_MNTS -ne $MPC ]; then
+    ESTR=""
+    if [ $PROCS -ne $MPC ]; then
+       ESTR="or $MPC"
+    fi
+    echo "sfs_mgr: incorrect number of MNT_POINTS ($NUM_MNTS) must be $PROCS $ESTR" >> $P_LOGFILE 2>&1
+    echo "sfs_mgr: incorrect number of MNT_POINTS ($NUM_MNTS) must be $PROCS $ESTR"
+    exit 1
+fi
+
+#
+# -----------------
+#
+trap "" $TRAP_NUMS
+
+#
+# clean up any 'old' sfs processes
+#
+if [ -f $SFS_PRM_PID ]; then
+    kill -2 `cat $SFS_PRM_PID` > /dev/null 2>&1
+    rm -f $SFS_PRM_PID
+fi
+if [ -f $SFS_PNT_PID ]; then
+    kill -2 `cat $SFS_PNT_PID` > /dev/null 2>&1
+    rm -f $SFS_PNT_PID
+fi
+if [ -f $SFS_SYNCD_PID ]; then
+    kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+    rm -f $SFS_SYNCD_PID
+fi
+
+#
+# Prime Client sfs_syncd logfile
+#
+S_LOGFILE=$WORK_DIR/syncd_$PRIME_CLIENT_NUM.log
+
+#
+# Determine the number of test runs (TOTAL_RUNS)
+# from user supplied values in sfs_rc
+#
+NUM_LOADS=0
+LOAD_ARRAY=""
+DEFAULT_LOAD=60
+#
+# get the number of LOAD elements (NUM_LOADS)
+#
+for i in $LOAD; do
+    NUM_LOADS=`expr $NUM_LOADS + 1`
+done
+#
+# if NUM_LOADS > 1 then the number of test runs (TOTAL_RUNS) = NUM_LOADS and
+# Report conflict if user specifies multiple LOAD elements as well as
+# NUM_RUNS > 1.
+#
+# if NUM_LOADS <= 1 then the number of test runs (TOTAL_RUNS) = NUM_RUNS
+#
+if [ "$NUM_LOADS" -gt 1 ]; then
+    TOTAL_RUNS=$NUM_LOADS
+    LOAD_ARRAY=$LOAD
+    if [ "$NUM_RUNS" -gt 1 ]; then
+       echo "Cannot specify an array of LOAD values as well as NUM_RUNS >1."
+       echo "Cannot specify an array of LOAD values as well as NUM_RUNS >1." \
+               >> $P_LOGFILE 2>&1
+       exit 1
+    fi
+else
+    TOTAL_RUNS=$NUM_RUNS
+    if [ "$NUM_LOADS" -eq 0 ]; then
+       LOAD=$DEFAULT_LOAD
+    fi
+    LOAD_ARRAY=$LOAD
+    i=1
+    while [ "$i" -lt "$NUM_RUNS" ]; do
+       LOAD_ARRAY="$LOAD_ARRAY `expr $LOAD + $i \* $INCR_LOAD`"
+       i=`expr $i + 1`
+    done
+fi
+
+#
+# Loop invariant parameters
+# create parameter strings here ... from sfs_rc values.
+# - SFS_PARAM : sfs parameters
+# - SFS_VPARAM : sfs validation parameters
+# - SFS_PRIME_PARAM : sfs_prime parameters
+SFS_PARAM=
+SFS_VPARAM=
+SFS_PRIME_PARAM=
+#
+# get runtime
+#
+if [ "$RUNTIME" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -t $RUNTIME"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -t $RUNTIME"
+fi
+
+#
+# get mixfile filename, if specified
+#
+if [ "$MIXFILE" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -m $WORK_DIR/$MIXFILE"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -m $WORK_DIR/$MIXFILE"
+fi
+
+#
+# get sfs DEBUG level
+#
+if [ "$DEBUG" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -d $DEBUG"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -d $DEBUG"
+fi
+
+#
+# get access percentage
+#
+if [ "$ACCESS_PCNT" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -a $ACCESS_PCNT"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -a $ACCESS_PCNT"
+fi
+
+#
+# get append percentage
+#
+if [ "$APPEND_PCNT" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -A $APPEND_PCNT"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -A $APPEND_PCNT"
+fi
+
+#
+# get block size
+#
+if [ "$BLOCK_SIZE" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -B $BLOCK_SIZE"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -B $BLOCK_SIZE"
+fi
+
+#
+# get block size filename, if specified
+#
+if [ "$BLOCK_FILE" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -b $WORK_DIR/$BLOCK_FILE"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -b $WORK_DIR/$BLOCK_FILE"
+fi
+
+#
+# get maximum number of outstanding biod reads
+#
+if [ "$BIOD_MAX_READS" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -R $BIOD_MAX_READS"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -R $BIOD_MAX_READS"
+fi
+
+#
+# get maximum number of outstanding biod writes
+#
+if [ "$BIOD_MAX_WRITES" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -W $BIOD_MAX_WRITES"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -W $BIOD_MAX_WRITES"
+fi
+
+#
+# get directory count
+#
+if [ "$DIR_COUNT" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -D $DIR_COUNT"
+fi
+
+#
+# get file count
+#
+if [ -n "$FILE_COUNT" ]; then
+  if [ "$FILE_COUNT" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -F $FILE_COUNT"
+  fi
+fi
+
+#
+# get symbolic link count
+#
+if [ "$SYMLINK_COUNT" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -S $SYMLINK_COUNT"
+fi
+
+#
+# set flag for raw data dump if option set
+#
+if [ "$DUMP" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -z"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -z"
+fi
+
+#
+# set flag for NFS/TCP if variable is "1" or "on"
+#
+if [ "$TCP" != "" ]
+then
+    if [ "$TCP" = "1" -o "$TCP" = "on" ]; then
+       SFS_PARAM="$SFS_PARAM -Q"
+       SFS_VPARAM="$SFS_VPARAM -Q"
+       SFS_PRIME_PARAM="$SFS_PRIME_PARAM -Q"
+    fi
+fi
+
+#
+# get number of processes
+#
+if [ "$PROCS" -ne 0 ]; then
+    SFS_PARAM="$SFS_PARAM -p $PROCS"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -p $PROCS"
+fi
+
+#
+# get warm-up value (allow 0 warmup)
+#
+if [ "$WARMUP_TIME" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -w $WARMUP_TIME"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -w $WARMUP_TIME"
+fi
+
+#
+# get sfs_prime sleep value
+#
+if [ "${PRIME_SLEEP:-0}" -gt 0 ]; then
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -s $PRIME_SLEEP"
+fi
+
+#
+# get file set percentage delta
+#
+if [ "$FILESET_DELTA" != "" ]; then
+    SFS_PARAM="$SFS_PARAM -f $FILESET_DELTA"
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -f $FILESET_DELTA"
+fi
+
+#
+# get sfs_prime timeout value
+#
+if [ "${PRIME_TIMEOUT:-0}" -gt 0 ]; then
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -x $PRIME_TIMEOUT"
+fi
+
+#
+# get populate only flag
+# 
+if [ "$POPULATE" != "" ]; then 
+    SFS_PARAM="$SFS_PARAM -P" 
+fi
+
+#
+# check for program that starts external monitoring
+#
+if [ "$PRIME_MON_SCRIPT" != "" ]; then
+    SFS_PRIME_PARAM="$SFS_PRIME_PARAM -k $WORK_DIR/$PRIME_MON_SCRIPT"
+    # check for parameters to the monitor program; use a different method
+    # to test for nonempty because the arguments may start with a hyphen,
+    # which would confuse the "test" command.
+    if [ "x$PRIME_MON_ARGS" != "x" ]; then
+       SFS_PRIME_PARAM="$SFS_PRIME_PARAM -K '$PRIME_MON_ARGS'"
+    fi
+
+    echo "" >> $P_LOGFILE
+fi
+
+#
+# Add clients to prime
+#
+SFS_PRIME_PARAM="$SFS_PRIME_PARAM $CLIENTS"
+
+#
+# get prime client hostname
+#
+SFS_PARAM="$SFS_PARAM -M $HOSTNAME_VAL"
+
+#### End client loop invariant section
+#
+# VALIDATE stuff
+#
+if [ "$VALIDATE" -gt 0 ]; then
+    echo "Executing SFS NFS Validation ..."
+    #
+    # if validate option used then take the first client
+    # from the CLIENT array and run the SFS validation
+    # suite using the first element on the MOUNT_PNTS list.
+
+    set `echo $CLIENTS`
+    VALID_CLIENT=$1
+
+    set `echo $MNT_POINTS`
+    VALID_MOUNT_PNT=$1
+
+    if [ $NUM_MNTS -eq 1 -a -f "$WORK_DIR/$VALID_MOUNT_PNT" ]
+    then
+       #
+       # If the mount point and is actually a file
+       # name then we assume that it is a file containing a list
+       # of mount points one line per client, possibly of the format
+       # hostname:path
+       #
+       MNT_PTS=`while read CLNT_LINE MNT_LINE
+       do
+           if [ $VALID_CLIENT = $CLNT_LINE ]
+           then
+               echo $MNT_LINE
+               break
+           fi
+       done < $WORK_DIR/$VALID_MOUNT_PNT`
+
+       set `echo $MNT_PTS`
+       VALID_MOUNT_PNT=$1
+    fi
+
+    echo "Starting SFS NFS validation on client ($VALID_CLIENT)"
+    echo "    $SFS_DIR/$SFS_PROG $SFS_VPARAM -V $VALID_LEVEL $VALID_MOUNT_PNT"
+    echo "Starting SFS Validation suite on client ($VALID_CLIENT)" \
+               > $P_VALFILE 2>&1
+    echo "    $SFS_DIR/$SFS_PROG $SFS_VPARAM -V $VALID_LEVEL $VALID_MOUNT_PNT" \
+               >> $P_VALFILE 2>&1
+
+    # Get canonical hostname of $VALID_CLIENT and see if it is the prime client.
+    client_name=`$RSH $VALID_CLIENT -l $SFS_USER 'hostname || uname -n' 2>/dev/null </dev/null`
+    if [ "$client_name" = $HOSTNAME_VAL ]; then
+       $SFS_DIR/$SFS_PROG $SFS_VPARAM -V $VALID_LEVEL $VALID_MOUNT_PNT \
+               >> $P_VALFILE 2>&1
+       # if error then clean-up and exit
+       if [ $? -ne 0 ]; then
+           echo "SFS NFS validation failed."
+           echo "See $P_VALFILE for results."
+           exit 1
+       else
+           echo "SFS NFS validation completed successfully."
+           echo "See $P_VALFILE for results."
+           exit 0
+       fi
+    else
+       $RSH $VALID_CLIENT -l $SFS_USER \
+           "( cd $WORK_DIR; \
+           $SFS_DIR/$SFS_PROG $SFS_VPARAM -V $VALID_LEVEL $VALID_MOUNT_PNT )" \
+           >> $P_VALFILE 2>&1
+       if [ $? -ne 0 ]; then
+           echo \
+           "sfs_mgr: can't run validation pass of sfs on client $VALID_CLIENT."
+           echo "            $RHOSTSCKMSG1"
+           echo \
+           "sfs_mgr: can't run validation pass of sfs on client $VALID_CLIENT." \
+                               >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG1"    >> $P_LOGFILE
+           exit 1
+       fi
+       # if error then clean-up and exit
+       tail -1 $P_VALFILE | grep -s 'validation completed successfully'
+       if [ $? -ne 0 ]; then
+           echo "SFS NFS validation failed."
+           echo "See $P_VALFILE for results."
+           echo "SFS NFS validation failed." >> $P_LOGFILE
+           echo "See $P_VALFILE for results." >> $P_LOGFILE
+           exit 1
+       else
+           echo "SFS NFS validation completed successfully."
+           echo "See $P_VALFILE for results."
+           echo "SFS NFS validation completed successfully." >> $P_LOGFILE
+           echo "See $P_VALFILE for results." >> $P_LOGFILE
+           exit 0
+       fi
+    fi
+fi
+
+
+#
+# Prime client /tmp logfiles - used for clean up
+#
+PRIME_LOG_FILES="/tmp/sfs_PC_sync \
+               /tmp/sfs_x$PRIME_CLIENT_NUM \
+               /tmp/sfs_CL$PRIME_CLIENT_NUM \
+               /tmp/sfs_mpr$PRIME_CLIENT_NUM \
+               /tmp/sfs_res*"
+
+#
+# start test
+# MAIN CLIENT LOOP
+#
+RUN=1
+for LOAD_INDEX in $LOAD_ARRAY; do
+    LOAD_VALUE=`expr $LOAD_INDEX / $NUM_CLIENTS`
+
+    export LOAD_VALUE LOAD_INDEX SUFFIX WORK_DIR
+
+    echo " ">>$P_LOGFILE
+    echo "$STARline" >> $P_LOGFILE
+    echo "$STARline" >> $P_OUTFILE
+
+    #
+    # clean up /tmp files
+    #
+    for i in $PRIME_LOG_FILES; do
+       if [ -f $i ]; then
+           if [ -w $i ]; then
+               rm $i
+           else
+               echo "sfs_mgr: error could not remove file - $i"
+               echo "sfs_mgr: error could not remove file - $i" >> $P_LOGFILE
+               exit 1
+           fi
+       fi
+    done
+    #
+    # restart the sfs_syncd process
+    #
+    if [ -f $SFS_SYNCD_PID ]; then
+       kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+       rm -f $SFS_SYNCD_PID
+    fi
+
+    trap "" $TRAP_NUMS
+
+    echo "Test Run $RUN of $TOTAL_RUNS" >>$P_LOGFILE
+    echo " " >>$P_LOGFILE
+    echo "    `date`"
+    $ECHO_NONL "     Executing run $RUN of $TOTAL_RUNS ... $NONL"
+    sh -c "$SFS_DIR/sfs_syncd >> $S_LOGFILE 2>&1 &"
+    sleep 15
+    echo "Started: sfs_syncd on Prime-Client ($HOSTNAME_VAL)" \
+       >> $P_LOGFILE
+
+    #
+    # start sfs on all the clients
+    #
+    CLIENTS_NUM=1
+    for i in $CLIENTS; do
+       #
+       # compose client's logfile name
+       #
+       if [ "$CLIENTS_NUM" -lt 10 ]; then
+           C_LOGFILE="$WORK_DIR"/sfsc00"$CLIENTS_NUM"."$SUFFIX"
+       elif [ "$CLIENTS_NUM" -lt 100 ]; then
+           C_LOGFILE="$WORK_DIR"/sfsc0"$CLIENTS_NUM"."$SUFFIX"
+       else
+           C_LOGFILE="$WORK_DIR"/sfsc"$CLIENTS_NUM"."$SUFFIX"
+       fi
+
+       #
+       # compose client's sfs_syncd logfile name
+       #
+       S_LOGFILE=$WORK_DIR/syncd_$CLIENTS_NUM.log
+
+       if [ $NUM_MNTS -eq 1 -a -f "$WORK_DIR/$MNT_POINTS" ]
+       then
+           #
+           # If there is only one mount point and it is actually a file
+           # name then we assume that it is a file containing a list
+           # of mount points one line per client, possibly of the format
+           # hostname:path
+           #
+           MNT_PTS=`while read CLNT_LINE MNT_LINE
+           do
+               if [ $i = $CLNT_LINE ]
+               then
+                   echo $MNT_LINE
+                   break
+               fi
+           done < $WORK_DIR/$MNT_POINTS`
+       else
+           #
+           # construct MNT_PTS for this particular CLIENTS_NUM (client)
+           # from MNT_POINTS, using total number of CLIENTS
+           # and PRCS [number of processes per client]
+           #
+           # PRCS must be a multiple of NUM_MNTS,
+           # no need to resequence the list of mount points
+           #
+           MNT_PTS="$MNT_POINTS"
+       fi
+
+       #
+       # if prime client in $CLIENT then start sfs locally
+       #
+        client_name=`$RSH $i -l $SFS_USER 'hostname || uname -n' 2>/dev/null </dev/null`
+       if [ "$client_name" = $HOSTNAME_VAL ]; then
+           echo "`date` $i start:" >>$P_LOGFILE
+           echo "        $SFS_PROG -N $CLIENTS_NUM -l $LOAD_VALUE $SFS_PARAM $MNT_PTS" \
+                                   >> $P_LOGFILE
+
+           trap "" $TRAP_NUMS
+           $SFS_DIR/$SFS_PROG -N $CLIENTS_NUM -l $LOAD_VALUE $SFS_PARAM $MNT_PTS \
+                       >> $C_LOGFILE 2>&1 &
+       else
+           #
+           # Cause remote client to cleanup
+           #
+           $RSH $i -l $SFS_USER "( cd $WORK_DIR; \
+               $SFS_DIR/sfs_mcr cleanup )" >>/dev/null 2>&1 </dev/null
+
+           #
+           # remotely start sfs_mcr script on clients
+           #
+           echo "`date` $i start:" >>$P_LOGFILE
+           echo "        $SFS_PROG -N $CLIENTS_NUM -l $LOAD_VALUE $SFS_PARAM $MNT_PTS" \
+               >> $P_LOGFILE
+
+           $RSH $i -l $SFS_USER "( cd $WORK_DIR; \
+               $SFS_DIR/sfs_mcr $SFS_PROG $SFS_DIR \
+               $S_LOGFILE $C_LOGFILE $CLIENTS_NUM \
+               -l $LOAD_VALUE $SFS_PARAM $MNT_PTS ) &"\
+               >>/dev/null 2>&1 </dev/null &
+       fi
+
+       #
+       # increment client num
+       #
+       CLIENTS_NUM=`expr $CLIENTS_NUM + 1`
+    done
+
+    #
+    # start the Prime client program, sfs_prime,
+    # and wait for completion
+    #
+    trap "" $TRAP_NUMS
+    $SFS_DIR/sfs_prime -l $LOAD_VALUE -C $P_SUMFILE $SFS_PRIME_PARAM \
+       > /tmp/sfs_mpr$PRIME_CLIENT_NUM 2>> $P_LOGFILE
+
+    #
+    # if error then clean-up set error flag, and break out
+    #
+    if [ $? -ne 0 ]; then
+       echo "sfs_mgr: sfs_prime returned an error, exiting"
+       echo "sfs_mgr: sfs_prime returned an error, exiting" \
+               >> $P_LOGFILE 2>&1
+       if [ -f $SFS_PNT_PID ]; then
+           kill -2 `cat $SFS_PNT_PID` > /dev/null 2>&1
+           rm -f $SFS_PNT_PID
+       fi
+       if [ -f $SFS_SYNCD_PID ]; then
+           kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+           rm -f $SFS_SYNCD_PID
+       fi
+       error=TRUE
+       break   # break out of for loop
+    fi
+
+    #
+    # record results
+    #
+    cat /tmp/sfs_mpr$PRIME_CLIENT_NUM >> $P_LOGFILE
+    cat /tmp/sfs_mpr$PRIME_CLIENT_NUM >> $P_OUTFILE
+    rm /tmp/sfs_mpr$PRIME_CLIENT_NUM >> $P_LOGFILE 2>&1
+
+    #
+    # increment RUN value and reset SFS_PARAM
+    #
+    RUN=`expr $RUN + 1`
+    echo " done"
+    #
+    echo "" >> $P_LOGFILE
+    echo "$STARline" >> $P_LOGFILE
+    echo "$STARline" >> $P_OUTFILE
+
+    #
+    # test run(s) completed
+    #
+done   # END OF MAIN CLIENT LOOP: 'for LOAD_INDEX in $LOAD_ARRAY'
+
+#
+# copy log files from clients
+#
+CLIENTS_NUM=1
+for i in $CLIENTS; do
+    #
+    # compose client's logfile name
+    #
+    if [ "$CLIENTS_NUM" -lt 10 ]; then
+       C_LOGFILE="$WORK_DIR"/sfsc00"$CLIENTS_NUM"."$SUFFIX"
+    elif [ "$CLIENTS_NUM" -lt 100 ]; then
+       C_LOGFILE="$WORK_DIR"/sfsc0"$CLIENTS_NUM"."$SUFFIX"
+    else
+       C_LOGFILE="$WORK_DIR"/sfsc"$CLIENTS_NUM"."$SUFFIX"
+    fi
+    #
+    # Copy over the logfiles. We copy the files to a temporary
+    # file on the chance that either the prime client is also
+    # a load generating client and we might rcp a file over
+    # itself, or the $WORK_DIR is NFS mounted by all clients,
+    # in which case we don't want to really remove the remote
+    # file since it is the same as the 'local' file on the
+    # prime. While not necessarily efficient, this is correct.
+    #
+    client_name=`$RSH $i -l $SFS_USER 'hostname || uname -n' 2>/dev/null </dev/null`
+    if [ $client_name != $HOSTNAME_VAL ]; then
+       #
+       # copy to temporary file: of different name than target
+       # in off chance /tmp is our $WORK_DIR
+       #
+       rcp "$SFS_USER"@"$i":"$C_LOGFILE" \
+               /tmp/sfs"$CLIENTS_NUM"."$SUFFIX"
+       if [ $? -ne 0 ]; then
+           echo "sfs_mgr: can't rcp $C_LOGFILE from client $i."
+           echo "            $RHOSTSCKMSG1"
+           echo "            $RHOSTSCKMSG2"
+           echo "sfs_mgr: can't rcp $C_LOGFILE from client $i." >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG1" >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG2" >> $P_LOGFILE
+           exit 1
+       fi
+       $RSH $i -l $SFS_USER "/bin/rm $C_LOGFILE"
+       if [ $? -ne 0 ]; then
+           echo "sfs_mgr: can't remove $C_LOGFILE on client $i."
+           echo "            $RHOSTSCKMSG1"
+           echo "sfs_mgr: can't remove $C_LOGFILE on client $i." >> $P_LOGFILE
+           echo "            $RHOSTSCKMSG1" >> $P_LOGFILE
+           exit 1
+       fi
+       mv /tmp/sfs"$CLIENTS_NUM"."$SUFFIX" "$C_LOGFILE"
+    fi
+    CLIENTS_NUM=`expr $CLIENTS_NUM + 1`
+done
+
+#
+# if we got an error, terminate sfs_mgr
+#
+if [ "$error" = TRUE ]; then
+    exit 1
+fi
+
+#
+# copy 'raw data dump' files from clients
+# only do this for one point, the final one--it dosn't make
+# sense to concatenate dumps from different loads
+#
+if [ "$DUMP" != "" ]; then
+    CLIENTS_NUM=1
+    for i in $CLIENTS; do
+       #
+       # compose client's raw dump logfile name
+       #
+       if [ "$CLIENTS_NUM" -lt 10 ]; then
+           CLNTNUM=00"$CLIENTS_NUM"
+       elif [ "$CLIENTS_NUM" -lt 100 ]; then
+           CLNTNUM=0"$CLIENTS_NUM"
+       else
+           CLNTNUM="$CLIENTS_NUM"
+       fi
+       PRC=$PROCS
+       if [ "$PRC" = "" ]; then
+           PRC=4
+       fi
+       PRCJ=0
+       while [ $PRCJ -lt $PRC ]; do
+           if [ "$PRCJ" -lt 10 ]; then
+               PROCNUM=00"$PRCJ"
+           elif [ "$PRCJ" -lt 100 ]; then
+               PROCNUM=0"$PRCJ"
+           else
+               PROCNUM="$PRCJ"
+           fi
+           RAWFILE=c${CLNTNUM}-p${PROCNUM}
+           #
+           # copy over the logfiles
+           # clean out (remove) originals
+           #
+           client_name=`$RSH $i -l $SFS_USER 'hostname || uname -n' 2>/dev/null </dev/null`
+           if [ $client_name != $HOSTNAME_VAL ]; then
+               $RSH $i -l $SFS_USER \
+                   cat /tmp/"$RAWFILE" \
+                   >> "$WORK_DIR"/"$RAWFILE"."$SUFFIX"
+               $RSH $i -l $SFS_USER \
+                   /bin/rm /tmp/"$RAWFILE"
+           else
+               cat /tmp/"$RAWFILE" \
+                   >> "$WORK_DIR"/"$RAWFILE"."$SUFFIX"
+               /bin/rm /tmp/"$RAWFILE"
+           fi
+           PRCJ=`expr $PRCJ + 1`
+       done
+       CLIENTS_NUM=`expr $CLIENTS_NUM + 1`
+    done
+fi
+
+#
+# cleanup processes before ending
+#
+if [ -f $SFS_PRM_PID ]; then
+    kill -2 `cat $SFS_PRM_PID` > /dev/null 2>&1
+    rm -f $SFS_PRM_PID
+fi
+if [ -f $SFS_PNT_PID ]; then
+    kill -2 `cat $SFS_PNT_PID` > /dev/null 2>&1
+    rm -f $SFS_PNT_PID
+fi
+if [ -f $SFS_SYNCD_PID ]; then
+    kill -2 `cat $SFS_SYNCD_PID` > /dev/null 2>&1
+    rm -f $SFS_SYNCD_PID
+fi
+
+#
+# cleanup temporary files
+#
+for i in $PRIME_LOG_FILES; do
+    if [ -f $i ]; then
+       if [ -w $i ]; then
+           rm $i
+       else
+           echo "sfs_mgr: error could not remove file - $i"
+           echo "sfs_mgr: error could not remove file - $i" >> $P_LOGFILE
+           exit 1
+       fi
+    fi
+done
+
+echo '========================================================================'\        >>$P_LOGFILE
+exit 0
diff --git a/TBBT/trace_play/sfs_rc b/TBBT/trace_play/sfs_rc
new file mode 100755 (executable)
index 0000000..fcf8cfd
--- /dev/null
@@ -0,0 +1,149 @@
+##############################################################################
+#
+#      @(#)sfs_rc      2.1     97/10/23
+#
+# Specify SFS parameters for sfs runs in this file.
+#
+# The following parameters are configurable within the SFS run and
+# reporting rules.
+#
+# See below for details.
+#
+# Example shows a run of 100 to 1000 ops/sec
+#
+LOAD="100"
+INCR_LOAD=100
+NUM_RUNS=10
+PROCS=4
+CLIENTS="client1 client2"
+MNT_POINTS="srvr:/a srvr:/b srvr:/c srvr:/d srvr:/e srvr:/f srvr:/g srvr:/h"
+BIOD_MAX_WRITES=2
+BIOD_MAX_READS=2
+TCP="on"
+NFS_VERSION="3"
+SFS_USER="`id | tr '()' '  ' | awk '{print $2}' `"
+SFS_DIR="`pwd`/bin"
+WORK_DIR="`pwd`/result"
+PRIME_MON_SCRIPT=""
+PRIME_MON_ARGS=""
+RSH="rsh"
+#
+# The following parameters are strictly defined within the SFS
+# run and reporting rules and may not be changed.
+#
+RUNTIME=300
+WARMUP_TIME=300
+MIXFILE=""
+ACCESS_PCNT=10
+APPEND_PCNT=70
+BLOCK_SIZE=8
+BLOCK_FILE=""
+DIR_COUNT=30
+FILE_COUNT=
+SYMLINK_COUNT=20
+#
+# The following parameters are useful for debugging or general system
+# tuning.  They may not be used during during a reportable SFS run.
+#
+DEBUG=
+DUMP=
+POPULATE=
+PRIME_SLEEP=0
+PRIME_TIMEOUT=0
+#
+# The default SFS options are implied if no values are assigned to
+# the variables. The variables and their meaning are as follows.
+#
+# The following parameters are configurable within the SFS run and
+# reporting rules.
+#
+#  LOAD                - array of numbers specifying the NFS loads
+#                (NFS calls per second) to be generated by all clients
+#                combined. The number of consecutive runs equals the size
+#                of the array and the peak load equals the largest value
+#                in the array.
+#  PROCS       - number of SFS sub-processes to generate NFS
+#                calls (DEFAULT PROCS = 4).
+#  MNT_POINTS  - string containing the mount points of NFS-mounted
+#                filesystems on the client which will be used in the test.
+#  BIOD_MAX_WRITES - maximum number of outstanding async (biod) writes
+#                (DEFAULT BIOD_MAX_WRITES = 2).
+#  BIOD_MAX_READS - maximum number of outstanding async (biod) reads
+#                (DEFAULT BIOD_MAX_READS = 2).
+#  TCP         - If set ("on") then use NFS/TCP behaviour rather
+#  NFS_VERSION - Set the version of the NFS protocol to use
+#                (DEFAULT [or unset] NFS_VERSION = 2)
+#  NUM_RUNS    - number indicating the number of multi-client runs. NUM_RUNS
+#                should only be used if the size of the LOAD array <= 1;
+#  INCR_LOAD   - number indicating the load increment factor in NFS call/sec.
+#                The first run generates LOAD calls/sec,
+#                subsequent runs are made with LOAD + (N * INCR_LOAD)
+#                calls/sec; where initial N = 0. INCR_LOAD should
+#                only be used if the size of the LOAD array <= 1.
+#  CLIENTS     - string containing client's host names; include the Prime-
+#                Client's host name if you will be using the Prime-Client to
+#                generate NFS loads.
+#  SFS_USER    - string containing the user account name that has appropriate
+#                permission to execute SFS on each of the clients. The
+#                user account name used on the Prime-Client should be added
+#                to the SFS_USER's .rhosts file on each of the clients.
+#  SFS_DIR     - string containing the directory path where the SFS
+#                executables are stored; should be the same for all systems
+#  WORK_DIR    - string containing directory path where the SFS output
+#                files are stored, this should be the same for all systems.
+#  RSH         - OS dependent version of remote shell executable ON THE
+#                PRIME CLIENT
+#  PRIME_MON_SCRIPT - string containing the name of a shell script used to
+#                control the start and stop of any external SFS
+#                processes like external performance monitors. The sample
+#                The sample shell script 'sfs_ext_mon' shows the
+#                expected semantics of the program.
+#  PRIME_MON_ARGS - string containing optional arguments that are passed
+#                to the PRIME_MON_SCRIPT.
+#
+# The following parameters are strictly defined within the SFS
+# run and reporting rules and may not be changed.
+#
+#  RUNTIME     - number of seconds to generate load
+#                (DEFAULT RUNTIME = 300).
+#  WARMUP_TIME - number of seconds to warmup
+#                (DEFAULT WARMUP_TIME = 300).
+#  MIXFILE     - string containing the NFS call distribution filename;
+#                a copy of $MIXFILE must be placed in the $WORK_DIR
+#                directory on the Prime_Client. The Prime-Client will
+#                propagate a copy to all the other clients in the test.
+#  ACCESS_PCNT - percent of total file set available for use by i/o
+#                operations that will be accessed.
+#                (DEFAULT ACCESS_PCNT = 10).
+#  APPEND_PCNT - percent of writes that append rather than overwrite
+#                (DEFAULT APPEND_PCNT = 70).
+#  BLOCK_SIZE  - number of KB in a block, up to 8 KB
+#                (DEFAULT BLOCK_SIZE = 8 ).
+#  BLOCK_FILE  - string containing the block transfer sizes filename.
+#                A copy of $BLOCK_FILE must be placed in the $WORK_DIR
+#                directory on the Prime_Client. The Prime-Client will
+#                propagate a copy to all the other clients in the test.
+#  DIR_COUNT   - number of files per directory to use for directory
+#                operations (DEFAULT DIR_COUNT = 30).
+#  FILE_COUNT  - number of files to use for read and write
+#                operations. By default, number of files is
+#                calculated from the specified LOAD and ACCESS_PCNT.
+#  SYMLINK_COUNT - number of symbolic links to use for symlink
+#                operations (DEFAULT SYMLINK_COUNT = 20).
+#
+# The following parameters are useful for debugging or general system
+# tuning.  They may not be used during during a reportable SFS run.
+#
+#  DUMP                - If set, dump raw data points at end of run
+#  POPULATE    - If set ("on") the only populate the file set and do
+#                run test.
+#
+#  PRIME_SLEEP - number of seconds Prime-Client should sleep after starting
+#                and stopping the SFS external monitoring facility and
+#                before sending synchronization message to clients. This is a
+#                provision to allow sufficient time for starting and stopping
+#                other performance monitoring utilities that could be used
+#                during SFS execution.
+#  PRIME_TIMEOUT - number of seconds Prime-Client should wait for a
+#                response from all the clients.  Zero indicates the
+#                default should be used.
diff --git a/TBBT/trace_play/sfs_suchown b/TBBT/trace_play/sfs_suchown
new file mode 100755 (executable)
index 0000000..49ac031
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+#
+# @(#)sfs_suchown      2.1     97/10/23
+#
+#  Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+#      All rights reserved.
+#              Standard Performance Evaluation Corporation (SPEC)
+#              6585 Merchant Place, Suite 100
+#              Warrenton, VA 20187
+#      This product contains benchmarks acquired from several sources who
+#      understand and agree with SPEC's goal of creating fair and objective
+#      benchmarks to measure computer performance.
+#
+#      This copyright notice is placed here only to protect SPEC in the
+#      event the source is misused in any manner that is contrary to the
+#      spirit, the goals and the intent of SPEC.
+#
+#      The source code is provided to the user or company under the license
+#      agreement for the SPEC Benchmark Suite for this product.
+
+#
+SPEC=${SPEC-0}
+
+if [ "$SPEC" != 0 ] ; then
+       rm -f $BENCH/bin/sfs
+       rm -f $BENCH/bin/sfs3
+       rm -f $BENCH/bin/sfs_syncd
+       rm -f $BENCH/bin/sfs_prime
+       rm -f $BENCH/bin/sfs_mgr
+       rm -f $BENCH/bin/sfs_mcr
+       rm -f $BENCH/bin/sfs_ext_mon
+fi
+
+#
+# If first argument is clobber, just remove executeables
+#
+if [ "$1" = "clobber" ]
+then
+       exit 0
+fi
+
+#
+# if first argument == -DRESVPORT then we must make executeable
+# setuid to root.
+#
+if [ "$1" = "-DRESVPORT" ]
+then
+       shift
+       echo "Setting root ownership on sfs setuid executable in order to"
+       echo "perform binding to privileged port. You may be asked to enter"
+       echo "the root password."
+       #
+       su $ROOTUSER <<EOF
+       chown root $*
+       chmod 04755 $*
+EOF
+fi
+
+#
+# if the SPEC tools are configured then move binaries to RESULTSDIR
+#
+if [ "$SPEC" != 0 ] ; then
+       mv sfs $BENCH/bin
+       mv sfs3 $BENCH/bin
+       mv sfs_syncd $BENCH/bin
+       mv sfs_prime $BENCH/bin
+       cp sfs_mgr $BENCH/bin
+       cp sfs_mcr $BENCH/bin
+       cp sfs_ext_mon $BENCH/bin
+fi
+exit 0
diff --git a/TBBT/trace_play/sfs_sync.x b/TBBT/trace_play/sfs_sync.x
new file mode 100755 (executable)
index 0000000..2a7066e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SFS sync daemon rpcgen configuration file
+ *     @(#)sfs_sync.x  2.1     97/10/23
+ *
+ * XXX Not currently used to generate source code
+ */
+
+const MAX_STR1_LEN = 31;
+const MAX_STR2_LEN = 2560;
+
+struct sync_string {
+       int     clnt_id;                        /* client number */
+       string  clnt_type<MAX_STR1_LEN>;        /* message type, hard coded */
+       string  clnt_transaction<MAX_STR1_LEN>; /* transaction id */
+       string  clnt_data<MAX_STR2_LEN>;        /* results strings */
+};
+
+program SFS {
+       version SFS {
+               int
+               SIGNAL_NULLPROC (void) = 0;
+               int
+               SIGNAL_SFS (sync_string) = 1;
+       } = 1;
+} = 100500;
diff --git a/TBBT/trace_play/t b/TBBT/trace_play/t
new file mode 100755 (executable)
index 0000000..9686a68
Binary files /dev/null and b/TBBT/trace_play/t differ
diff --git a/TBBT/trace_play/t.c b/TBBT/trace_play/t.c
new file mode 100644 (file)
index 0000000..45baab2
--- /dev/null
@@ -0,0 +1,6 @@
+main()
+{
+       int i = 1;
+       i <<= 2;
+       printf("%d\n", i);
+}