Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / sfs_3_ops.c
1 #ifndef lint
2 static char sfs_3_opsSid[] = "@(#)sfs_3_ops.c   2.1     97/10/23";
3 #endif
4
5 /*
6  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
7  *      All rights reserved.
8  *              Standard Performance Evaluation Corporation (SPEC)
9  *              6585 Merchant Place, Suite 100
10  *              Warrenton, VA 20187
11  *
12  *      This product contains benchmarks acquired from several sources who
13  *      understand and agree with SPEC's goal of creating fair and objective
14  *      benchmarks to measure computer performance.
15  *
16  *      This copyright notice is placed here only to protect SPEC in the
17  *      event the source is misused in any manner that is contrary to the
18  *      spirit, the goals and the intent of SPEC.
19  *
20  *      The source code is provided to the user or company under the license
21  *      agreement for the SPEC Benchmark Suite for this product.
22  */
23
24 /*****************************************************************
25  *                                                               *
26  *      Copyright 1991,1992  Legato Systems, Inc.                *
27  *      Copyright 1991,1992  Auspex Systems, Inc.                *
28  *      Copyright 1991,1992  Data General Corporation            *
29  *      Copyright 1991,1992  Digital Equipment Corporation       *
30  *      Copyright 1991,1992  Interphase Corporation              *
31  *      Copyright 1991,1992  Sun Microsystems, Inc.              *
32  *                                                               *
33  *****************************************************************/
34
35 /*
36  * ---------------------- sfs_3_ops.c ---------------------
37  *
38  *      RPC routines to implement the NFS protocol.
39  *
40  *.Local Routines
41  *      int op_null(void)
42  *      int op_getattr(void)
43  *      int op_setattr(int)
44  *      int op_lookup(void)
45  *      int op_access(void)
46  *      int op_readlink(void)
47  *      int op_read(int)
48  *      int op_write(int, int, stable_how)
49  *      int op_create(void)
50  *      int op_mkdir(void);
51  *      int op_symlink(void);
52  *      int op_mknod(void);
53  *      int op_remove(void);
54  *      int op_rmdir(void);
55  *      int op_rename(void);
56  *      int op_link(void);
57  *      int op_readdir(void);
58  *      int op_readdirplus(void);
59  *      int op_fsstat(void);
60  *      int op_fsinfo(void);
61  *      int op_pathconf(void);
62  *      int op_commit(void);
63  *
64  *.Revision_History
65  *      30-Jun-94       ChakChung Ng    Created.
66  */
67
68
69 /*
70  * -------------------------  Include Files  -------------------------
71  */
72
73 /*
74  * ANSI C headers
75  */
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <errno.h>
80
81 #include <sys/types.h>
82 #include <sys/stat.h>
83
84 #include <unistd.h>
85
86 #include "sfs_c_def.h"
87
88 /*
89  * --------------------  Local NFS ops function --------------------
90  */
91 static int op_null(void);
92 static int op_getattr(void);
93 static int op_setattr(int);
94 static int op_lookup(void);
95 static int op_access(void);
96 static int op_readlink(void);
97 static int op_read(int);
98 static int op_write(int, int, stable_how);
99 static int op_create(void);
100 static int op_mkdir(void);
101 static int op_symlink(void);
102 static int op_mknod(void);
103 static int op_remove(void);
104 static int op_rmdir(void);
105 static int op_rename(void);
106 static int op_link(void);
107 static int op_readdir(void);
108 static int op_readdirplus(void);
109 static int op_fsstat(void);
110 static int op_fsinfo(void);
111 static int op_pathconf(void);
112 static int op_commit(void);
113 static int op_nosys(void);
114 static char *nfs3_strerror(int);
115
116
117 /*
118  * --------------------  NFS ops vector --------------------
119  */
120 /*
121  * per operation information
122  */
123 static sfs_op_type nfsv3_Ops[] = {
124
125 /* name        mix   function         op    call  no  req  req  req  results */
126 /*             pcnt                  class  targ call pcnt cnt  targ         */
127
128  { "null",        0, op_null,        Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
129  { "getattr",    11, op_getattr,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
130  { "setattr",     1, op_setattr,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
131  { "root",        0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
132  { "lookup",     27, op_lookup,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
133  { "readlink",    7, op_readlink,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
134  { "read",       18, op_read,        Read,    0,  0,  0.0,  0,   0,  { 0, }},
135  { "wrcache",     0, op_nosys,       Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
136  { "write",       9, op_write,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
137  { "create",      1, op_create,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
138  { "remove",      1, op_remove,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
139  { "rename",      0, op_rename,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
140  { "link",        0, op_link,        Write,   0,  0,  0.0,  0,   0,  { 0, }},
141  { "symlink",     0, op_symlink,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
142  { "mkdir",       0, op_mkdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
143  { "rmdir",       0, op_rmdir,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
144  { "readdir",     2, op_readdir,     Read,    0,  0,  0.0,  0,   0,  { 0, }},
145  { "fsstat",      1, op_fsstat,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
146  { "access",      7, op_access,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
147  { "commit",      5, op_commit,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
148  { "fsinfo",      1, op_fsinfo,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
149  { "mknod",       0, op_mknod,       Write,   0,  0,  0.0,  0,   0,  { 0, }},
150  { "pathconf",    0, op_pathconf,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
151  { "readdirplus", 9, op_readdirplus, Read,   0,  0,  0.0,  0,   0,  { 0, }},
152  { "TOTAL",     100, 0,              Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
153 };
154
155 sfs_op_type *Ops;
156
157 /*
158  * --------------------  RPC routines for NFS protocol --------------------
159  */
160
161 void
162 init_ops(void)
163 {
164     Ops = nfsv3_Ops;
165     nfs_version = NFS_V3;
166 }
167
168 /*
169  * The routines below attempt to do over-the-wire operations.
170  * Each op tries to cause one or more of a particular
171  * NFS operation to go over the wire.  OPs return the success
172  * of their NFS call(s).  Each OP records how many calls it
173  * actually made in global data.
174  *
175  * An array of file information is kept for files existing in
176  * the test directory.  File handles, attributes, names, etc
177  * are stored in this array.
178  *
179  */
180
181 /*
182  * Generic catch all for operations not covered by this protocol.
183  */
184 static int
185 op_nosys(int i)
186 {
187         RFS_ASSERT (dep_tab[i].flag == TO_BE_SENT);
188         dep_tab[i].flag = DONE;
189     Ops[TOTAL].results.bad_calls++;
190         if (i==min_index)
191                 adjust_min_index ();
192     return(0);
193 }
194
195 static struct biod_req *
196 get_biod_reqp (int dep_tab_index)
197 {
198         static int index = 0;
199         int i;
200
201         for (i=0; i<max_biod_reqs; i++, index = (index+1)%max_biod_reqs) {
202                 if (biod_reqp[index].in_use == FALSE) {
203                         biod_reqp[index].in_use = TRUE;
204                         dep_tab[dep_tab_index].biod_index = index;
205                         biod_req[index].dep_tab_index = dep_tab_index;
206                         return (biod_reqp+index);
207                 }
208         }
209 }
210
211 static int
212 op_null(int i)
213 {
214     sfs_op_type         *op_ptr;        /* per operation info */
215     enum clnt_stat      rpc_stat;       /* result from RPC call */
216     struct ladtime      start;
217     struct ladtime      stop;
218     int                 ret;            /* ret val == call success */
219
220         struct biod_req * reqp;
221         struct ladtime call_timeout;
222
223         if (dep_tab[i].flag == SENT)
224                 goto RECEIVE_REPLY;
225
226     op_ptr = &Ops[NULLCALL];
227         reqp = get_biod_reqp(i);
228
229         call_timeout.sec = Nfs_timers[op_ptr->call_class].tv_sec;
230         call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
231
232     ret = 0;
233
234     /* make the call */
235     sfs_gettime(&reqp->start);
236         reqp->xid = boid_clnt_call(NFS_client, NFS3PROC_NULL, xdr_void, (char *)0);
237         if (reqp->xid != 0) {
238                 reqp->timeout = reqp->start;
239                 ADDTIME (reqp->timeout, call_timeout);
240                 num_out_reqs++;
241                 dep_tab[i].flag = SENT;
242         } else 
243                 RFS_ASSERT (0);
244
245         return 0;
246
247 RECEIVE_REPLY:
248     rpc_stat = clnt_call(NFS_client, NFSPROC3_NULL,
249                         xdr_void, (char *)0, xdr_void, (char *)0,
250                         (Current_test_phase < Warmup_phase)
251                                  ? Nfs_timers[Init]
252                                  : Nfs_timers[op_ptr->call_class]);
253     sfs_gettime(&stop);
254     Cur_time = stop;
255
256     if (rpc_stat == RPC_SUCCESS) {
257         sfs_elapsedtime(op_ptr, &start, &stop);
258         op_ptr->results.good_calls++;
259         Ops[TOTAL].results.good_calls++;
260         ret++;
261     } else {
262         if (DEBUG_CHILD_ERROR) {
263              (void) fprintf(stderr, "%s: null_op call RPC error %d\n",
264                                                 sfs_Myname, rpc_stat);
265         }
266         op_ptr->results.bad_calls++;
267         Ops[TOTAL].results.bad_calls++;
268     }
269     return(ret);
270
271 } /* op_null */
272
273
274 static int
275 op_getattr(void)
276 {
277     sfs_op_type         *op_ptr;        /* per operation info */
278     GETATTR3args        args;           /* fh to do op on */
279     GETATTR3res         reply;          /* the reply */
280     enum clnt_stat      rpc_stat;       /* result from RPC call */
281     struct ladtime      start;
282     struct ladtime      stop;
283     int                 ret;            /* ret val == call success */
284
285     op_ptr = &Ops[GETATTR];
286     ret = 0;
287
288     /* set up the arguments */
289     (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
290                                                         sizeof (nfs_fh3));
291
292     /* make the call */
293     sfs_gettime(&start);
294     rpc_stat = clnt_call(NFS_client, NFSPROC3_GETATTR,
295                         xdr_GETATTR3args, (char *) &args,
296                         xdr_GETATTR3res, (char *) &reply,
297                         (Current_test_phase < Warmup_phase)
298                                  ? Nfs_timers[Init]
299                                  : Nfs_timers[op_ptr->call_class]);
300     sfs_gettime(&stop);
301     Cur_time = stop;
302
303     if (rpc_stat == RPC_SUCCESS) {
304         if (reply.status == NFS3_OK) {
305             (void) memmove((char *) &Cur_file_ptr->attributes3,
306                                 (char *) &reply.resok.obj_attributes,
307                                 sizeof (Cur_file_ptr->attributes3));
308             Cur_file_ptr->size = fh_size(Cur_file_ptr);
309         } else {
310             if (DEBUG_CHILD_ERROR) {
311                  (void) fprintf(stderr,
312                         "%s: getattr call NFS error %s on file %d\n",
313                         sfs_Myname, nfs3_strerror(reply.status),
314                         Cur_file_ptr->unique_num);
315             }
316         }
317         sfs_elapsedtime(op_ptr, &start, &stop);
318         op_ptr->results.good_calls++;
319         Ops[TOTAL].results.good_calls++;
320         ret++;
321     } else {
322         if (DEBUG_CHILD_ERROR) {
323              (void) fprintf(stderr,
324                         "%s: getattr call RPC error %d on file %d\n",
325                         sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
326         }
327         op_ptr->results.bad_calls++;
328         Ops[TOTAL].results.bad_calls++;
329     }
330     return(ret);
331
332 } /* op_getattr */
333
334
335 /*
336  * perform an RPC setattr operation.  If 'truncate_size' is non-negative,
337  * truncate the file to that size.
338  */
339 static int
340 op_setattr(
341     int         truncate_size)
342 {
343     sfs_op_type         *op_ptr;        /* per operation info */
344     SETATTR3args        args;
345     SETATTR3res         reply;          /* the reply */
346     enum clnt_stat      rpc_stat;       /* result from RPC call */
347     struct ladtime      start;
348     struct ladtime      stop;
349     int                 ret;            /* ret val == call success */
350
351     op_ptr = &Ops[SETATTR];
352     ret = 0;
353
354     /* set up the arguments */
355     (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
356                                                         sizeof (nfs_fh3));
357     args.new_attributes.mode.set_it = TRUE;
358     args.new_attributes.mode.mode = (uint32_t) 0666;
359     args.new_attributes.uid.set_it = FALSE;
360     args.new_attributes.uid.uid = (uint32_t) -1;
361     args.new_attributes.gid.set_it = FALSE;
362     args.new_attributes.gid.gid = (uint32_t) -1;
363     args.new_attributes.size.set_it = FALSE;
364     args.new_attributes.size.size._p._u = (uint32_t) ~0;
365     args.new_attributes.size.size._p._l = (uint32_t) -1;
366     args.new_attributes.atime.set_it = TRUE;
367     args.new_attributes.atime.atime.seconds = Cur_time.esec;
368     args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
369     args.new_attributes.mtime.set_it = TRUE;
370     args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
371     args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
372     args.guard.check = FALSE;
373
374     /* handle file truncations */
375     if (truncate_size >= 0) {
376         args.new_attributes.size.set_it = TRUE;
377         args.new_attributes.size.size._p._u = (uint32_t) 0;
378         if (truncate_size > Cur_file_ptr->attributes3.size._p._l)
379             args.new_attributes.size.size._p._l = (uint32_t) 0;
380         else
381             args.new_attributes.size.size._p._l =
382                 (uint32_t) Cur_file_ptr->attributes3.size._p._l -
383                                                                 truncate_size;
384     }
385
386     /* make the call */
387     sfs_gettime(&start);
388     rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
389                         xdr_SETATTR3args, (char *) &args,
390                         xdr_SETATTR3res, (char *) &reply,
391                         (Current_test_phase < Warmup_phase)
392                                  ? Nfs_timers[Init]
393                                  : Nfs_timers[op_ptr->call_class]);
394
395     sfs_gettime(&stop);
396     Cur_time = stop;
397
398     if (rpc_stat == RPC_SUCCESS) {
399         if (reply.status == NFS3_OK) {
400             (void) memmove((char *) &Cur_file_ptr->attributes3,
401                                 (char *) &reply.resok.obj_wcc.after.attr,
402                                 sizeof (Cur_file_ptr->attributes3));
403             Cur_file_ptr->size = fh_size(Cur_file_ptr);
404         } else {
405             if (DEBUG_CHILD_ERROR) {
406                  (void) fprintf(stderr,
407                         "%s: setattr call NFS error %s on file %d\n",
408                         sfs_Myname, nfs3_strerror(reply.status),
409                         Cur_file_ptr->unique_num);
410             }
411         }
412         sfs_elapsedtime(op_ptr, &start, &stop);
413         op_ptr->results.good_calls++;
414         Ops[TOTAL].results.good_calls++;
415         ret++;
416     } else {
417         if (DEBUG_CHILD_ERROR) {
418              (void) fprintf(stderr,
419                         "%s: setattr call RPC error %d on file %d\n",
420                         sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
421         }
422         op_ptr->results.bad_calls++;
423         Ops[TOTAL].results.bad_calls++;
424     }
425     return(ret);
426
427 } /* op_setattr */
428
429
430 static int
431 op_lookup(void)
432 {
433     sfs_op_type         *op_ptr;        /* per operation info */
434     LOOKUP3args         args;
435     LOOKUP3res          reply;          /* the reply */
436     enum clnt_stat      rpc_stat;       /* result from RPC call */
437     struct ladtime      start;
438     struct ladtime      stop;
439     int                 ret;            /* ret val == call success */
440
441     op_ptr = &Ops[LOOKUP];
442     ret = 0;
443
444     /* set up the arguments */
445     (void) memmove((char *) &args.what.dir, (char *) &Cur_file_ptr->dir->fh3,
446                                                         sizeof (nfs_fh3));
447     args.what.name = Cur_filename;
448     (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
449
450     /* make the call */
451     sfs_gettime(&start);
452     rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
453                         xdr_LOOKUP3args, (char *) &args,
454                         xdr_LOOKUP3res, (char *) &reply,
455                         (Current_test_phase < Warmup_phase)
456                                  ? Nfs_timers[Init]
457                                  : Nfs_timers[op_ptr->call_class]);
458     sfs_gettime(&stop);
459     Cur_time = stop;
460
461     if (rpc_stat == RPC_SUCCESS) {
462         if (reply.status == NFS3_OK) {
463             Cur_file_ptr->state = Exists;
464             (void) memmove((char *) &Cur_file_ptr->fh3,
465                         (char *) &reply.resok.object,
466                         sizeof (nfs_fh3));
467             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
468             (void) memmove((char *) &Cur_file_ptr->attributes3,
469                                 (char *) &reply.resok.obj_attributes.attr,
470                                 sizeof (Cur_file_ptr->attributes3));
471             Cur_file_ptr->size = fh_size(Cur_file_ptr);
472         } else {
473             /* We do lookup Nonexistent and this is not an error */
474             if (reply.status != NFS3ERR_NOENT ||
475                         Cur_file_ptr->state != Nonexistent) {
476                 if (DEBUG_CHILD_ERROR) {
477                      (void) fprintf(stderr,
478                         "%s: lookup call NFS error %s on file %d\n",
479                         sfs_Myname, nfs3_strerror(reply.status),
480                         Cur_file_ptr->unique_num);
481                 }
482             }
483         }
484         sfs_elapsedtime(op_ptr, &start, &stop);
485         op_ptr->results.good_calls++;
486         Ops[TOTAL].results.good_calls++;
487         ret++;
488     } else {
489         if (DEBUG_CHILD_ERROR) {
490              (void) fprintf(stderr, "%s: lookup call RPC error %d on file %d\n",
491                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
492         }
493         op_ptr->results.bad_calls++;
494         Ops[TOTAL].results.bad_calls++;
495     }
496     return(ret);
497
498 } /* op_lookup */
499
500
501 static int
502 op_access(void)
503 {
504     sfs_op_type         *op_ptr;        /* per operation info */
505     ACCESS3args         args;
506     ACCESS3res          reply;          /* the reply */
507     enum clnt_stat      rpc_stat;       /* result from RPC call */
508     struct ladtime      start;
509     struct ladtime      stop;
510     int                 ret;            /* ret val == call success */
511
512     op_ptr = &Ops[ACCESS];
513     ret = 0;
514
515     /* set up the arguments */
516     (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->dir->fh3,
517                                 sizeof (nfs_fh3));
518     args.access = ACCESS3_MODIFY;
519
520     /* make the call */
521     sfs_gettime(&start);
522     rpc_stat = clnt_call(NFS_client, NFSPROC3_ACCESS,
523                         xdr_ACCESS3args, (char *) &args,
524                         xdr_ACCESS3res, (char *) &reply,
525                         (Current_test_phase < Warmup_phase)
526                                  ? Nfs_timers[Init]
527                                  : Nfs_timers[op_ptr->call_class]);
528     sfs_gettime(&stop);
529     Cur_time = stop;
530
531     if (rpc_stat == RPC_SUCCESS) {
532         if (reply.status == NFS3_OK) {
533             Cur_file_ptr->state = Exists;
534             (void) memmove((char *) &Cur_file_ptr->attributes3,
535                                 (char *) &reply.resok.obj_attributes.attr,
536                                 sizeof (Cur_file_ptr->attributes3));
537             Cur_file_ptr->size = fh_size(Cur_file_ptr);
538         } else {
539             if (DEBUG_CHILD_ERROR) {
540                  (void) fprintf(stderr,
541                         "%s: access call NFS error %s on file %d\n",
542                         sfs_Myname, nfs3_strerror(reply.status),
543                         Cur_file_ptr->unique_num);
544             }
545         }
546         sfs_elapsedtime(op_ptr, &start, &stop);
547         op_ptr->results.good_calls++;
548         Ops[TOTAL].results.good_calls++;
549         ret++;
550     } else {
551         if (DEBUG_CHILD_ERROR) {
552              (void) fprintf(stderr, "%s: access call RPC error %d on file %d\n",
553                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
554         }
555         op_ptr->results.bad_calls++;
556         Ops[TOTAL].results.bad_calls++;
557     }
558     return(ret);
559
560 } /* op_access */
561
562
563 static int
564 op_readlink(void)
565 {
566     sfs_op_type         *op_ptr;                /* per operation info */
567     READLINK3args       args;                   /* the args */
568     READLINK3res        reply;                  /* the reply */
569     char                sym_data[NFS_MAXPATHLEN];
570     enum clnt_stat      rpc_stat;               /* result from RPC call */
571     struct ladtime      start;
572     struct ladtime      stop;
573     int                 ret;                    /* ret val == call success */
574
575     op_ptr = &Ops[READLINK];
576     ret = 0;
577
578     /* set up the arguments */
579     /*
580      * Note: this symlink may be bogus because SYMLINK does
581      * not return a symlink ... only a status.  So unless we have
582      * done a LOOKUP on this guy, the symlink will probably be bad.
583      * If it is bad it shows up as a symlink error in the results.
584      */
585     (void) memmove((char *) &args.symlink,
586                         (char *) &Cur_file_ptr->fh3,
587                         sizeof (nfs_fh3));
588
589     /* Have lower layers fill in the data directly. */
590     reply.resok.data = sym_data;
591
592     /* make the call now */
593     sfs_gettime(&start);
594     rpc_stat = clnt_call(NFS_client, NFSPROC3_READLINK,
595                         xdr_READLINK3args, (char *) &args,
596                         xdr_READLINK3res, (char *) &reply,
597                         (Current_test_phase < Warmup_phase)
598                                  ? Nfs_timers[Init]
599                                  : Nfs_timers[op_ptr->call_class]);
600     sfs_gettime(&stop);
601     Cur_time = stop;
602
603     if (rpc_stat == RPC_SUCCESS) {
604         if (reply.status == NFS3_OK) {
605             if (DEBUG_CHILD_RPC) {
606                 (void) fprintf(stderr, "%s: READLINK on %s returned %s\n",
607                                     sfs_Myname, Cur_filename, sym_data);
608                 (void) fflush(stderr);
609             }
610         } else {
611             if (DEBUG_CHILD_ERROR) {
612                  (void) fprintf(stderr,
613                         "%s: readlink call NFS error %s on file %d\n",
614                         sfs_Myname, nfs3_strerror(reply.status),
615                         Cur_file_ptr->unique_num);
616             }
617         }
618         sfs_elapsedtime(op_ptr, &start, &stop);
619         op_ptr->results.good_calls++;
620         Ops[TOTAL].results.good_calls++;
621         ret++;
622     } else {
623         if (DEBUG_CHILD_ERROR) {
624              (void) fprintf(stderr,
625                         "%s: readlink call RPC error %d on file %d\n",
626                         sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
627         }
628         op_ptr->results.bad_calls++;
629         Ops[TOTAL].results.bad_calls++;
630     }
631     return(ret);
632
633 } /* op_readlink */
634
635
636 /*
637  * perform an RPC read operation of length 'xfer_size'
638  */
639 static int
640 op_read(
641     int                         xfer_size)
642 {
643     sfs_op_type                 *op_ptr;        /* per operation info */
644     int                         cur_cnt;
645     int                         max_cnt;        /* packet ctrs */
646     char                        buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
647     READ3args                   args;
648     READ3res                    reply;          /* the reply */
649     enum clnt_stat              rpc_stat;       /* result from RPC call */
650     struct ladtime              start;
651     struct ladtime              stop;
652     int                         size;
653     int                         j;
654     int                         ret;            /* ret val == call success */
655
656     op_ptr = &Ops[READ];
657     ret = 0;
658
659     /* set up the arguments */
660     (void) memmove((char *) &args.file,
661                         (char *) &Cur_file_ptr->fh3,
662                         sizeof (nfs_fh3));
663
664     /*
665      * Don't allow a read of less than one block size
666      */
667     if (xfer_size < Bytes_per_block)
668         xfer_size = Bytes_per_block;
669
670     /*
671      * randomly choose an offset that is a multiple of the block size
672      * and constrained by making the transfer fit within the file
673      */
674     args.offset._p._u = 0;
675     if (Cur_file_ptr->attributes3.size._p._l > xfer_size)
676         args.offset._p._l = Bytes_per_block * (sfs_random() %
677                         (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
678                         / Bytes_per_block) + 1));
679     else
680         args.offset._p._l = 0;
681
682     /* Have lower layers fill in the data directly.  */
683     reply.resok.data.data_len = 0;
684     reply.resok.data.data_val = buf;
685
686     /* first read the whole buffers, then the fragment */
687     for (j = 0; j < 2; j++) {
688
689         if (j == 0) {
690             size = Bytes_per_block;
691             max_cnt = xfer_size / Bytes_per_block;
692         } else {
693             /* 1KB - (Kb_per_block -1) KB fragment */
694             size = xfer_size % Bytes_per_block;
695             max_cnt = 1;
696         }
697         if (size == 0)
698             continue;
699
700         /* check our stats to see if this would overflow */
701         if (!Timed_run) {
702             if (op_ptr->target_calls > 0) {
703                 if ((op_ptr->results.good_calls + max_cnt)
704                      > op_ptr->target_calls) {
705                     max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
706                 }
707             }
708         }
709
710         args.count = size;
711
712         if (DEBUG_CHILD_RPC) {
713             (void) fprintf(stderr, "read: %d buffers\n", max_cnt);
714             (void) fflush(stderr);
715         }
716
717         /* make the call(s) now */
718         for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
719
720             /* capture length for possible dump */
721             Dump_length = fh_size(Cur_file_ptr);
722  
723             sfs_gettime(&start);
724             rpc_stat = clnt_call(NFS_client, NFSPROC3_READ,
725                                 xdr_READ3args, (char *) &args,
726                                 xdr_READ3res, (char *) &reply,
727                                 (Current_test_phase < Warmup_phase)
728                                      ? Nfs_timers[Init]
729                                      : Nfs_timers[op_ptr->call_class]);
730             sfs_gettime(&stop);
731             Cur_time = stop;
732
733             /* capture count and offset for possible dump */
734             Dump_count = (rpc_stat == RPC_SUCCESS && reply.status == NFS3_OK)
735                             ? reply.resok.data.data_len : 0;
736             Dump_offset = args.offset._p._l;
737
738             if (rpc_stat == RPC_SUCCESS) {
739                 if (reply.status == NFS3_OK) {
740                     Cur_file_ptr->state = Exists;
741                     (void) memmove((char *) &Cur_file_ptr->attributes3,
742                                 (char *) &reply.resok.file_attributes.attr,
743                                 sizeof (Cur_file_ptr->attributes3));
744                     Cur_file_ptr->size = fh_size(Cur_file_ptr);
745                     size = reply.resok.data.data_len;
746
747                     if (DEBUG_CHILD_RPC) {
748                         (void) fprintf(stderr, "%s: READ %s %d bytes\n",
749                                            sfs_Myname, Cur_filename, size);
750                         (void) fflush(stderr);
751                     }
752                     args.offset._p._l += size;
753                 } else {
754                     if (DEBUG_CHILD_ERROR) {
755                          (void) fprintf(stderr,
756                                 "%s: read call NFS error %s on file %d\n",
757                                         sfs_Myname,
758                                         nfs3_strerror(reply.status),
759                                         Cur_file_ptr->unique_num);
760                     }
761                 }
762                 sfs_elapsedtime(op_ptr, &start, &stop);
763                 op_ptr->results.good_calls++;
764                 Ops[TOTAL].results.good_calls++;
765                 ret++;
766             } else {
767                 if (DEBUG_CHILD_ERROR) {
768                      (void) fprintf(stderr,
769                                 "%s: read call RPC error %d on file %d\n",
770                             sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
771                 }
772                 op_ptr->results.bad_calls++;
773                 Ops[TOTAL].results.bad_calls++;
774             }
775         } /* for reading max_cnt packets */
776     } /* for buffers and fragments */
777     return(ret);
778
779 } /* op_read */
780
781 char *
782 init_write_buffer(
783     void)
784 {
785     uint32_t *bp;
786     static uint32_t write_buf[DEFAULT_MAX_BUFSIZE / sizeof(uint32_t)];
787     uint32_t *be  = write_buf + (sizeof(write_buf) /
788                                                         sizeof(uint32_t));
789
790     if (write_buf[0] != (uint32_t)0xdeadbeef) {
791         for (bp = write_buf; bp < be; bp++)
792             *bp = (uint32_t)0xdeadbeef;
793     }
794     return (char *)write_buf;
795 }
796
797
798 /*
799  * Perform and RPC write operation of length 'xfer_size'.  If 'append_flag'
800  * is true, then write the data to the end of the file.
801  *
802  * If the stab_flag is set to UNSTABLE we issue the requests and then
803  * issue a op_commit to sync the data.
804  */
805 static int
806 op_write(
807     int                 xfer_size,
808     int                 append_flag,
809     stable_how          stab_flag)
810 {
811     sfs_op_type                 *op_ptr;        /* per operation info */
812     static char                 *buf = NULL;    /* the data buffer */
813     unsigned int                size;           /* size of data write */
814     int                         cur_cnt;        /* controls # NFS calls */
815     int                         max_cnt;
816     WRITE3args                  args;
817     WRITE3res                   reply;          /* the reply */
818     enum clnt_stat              rpc_stat;       /* result from RPC call */
819     struct ladtime              start;
820     struct ladtime              stop;
821     int                         j;
822     int                         ret;            /* ret val == call success */
823
824     /*
825      * For now we treat DATA_SYNC to be the same as FILE_SYNC.
826      */
827     if (stab_flag == DATA_SYNC)
828         stab_flag = FILE_SYNC;
829
830     /*
831      * Initialize write buffer to known value
832      */
833     if (buf == NULL) {
834         buf = init_write_buffer();
835     }
836
837     op_ptr = &Ops[WRITE];
838     ret = 0;
839
840     /* set up the arguments */
841     (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
842                 sizeof (nfs_fh3));
843     args.offset._p._u = 0;
844     if (append_flag == 1) {
845         args.offset._p._l = Cur_file_ptr->attributes3.size._p._l;
846     } else {
847         /*
848          * randomly choose an offset that is a multiple of the block size
849          * and constrained by making the transfer fit within the file
850          */
851         if (Cur_file_ptr->attributes3.size._p._l > xfer_size) {
852             args.offset._p._l = Bytes_per_block * (sfs_random() %
853                             (((Cur_file_ptr->attributes3.size._p._l - xfer_size)
854                             / Bytes_per_block) + 1));
855         } else
856             args.offset._p._l = 0;
857     }
858
859     /* stab_flag has to be set in op() in sfs_3_chd.c */
860     args.stable = stab_flag;
861
862     /* first write the whole buffers, then the fragment */
863     for (j = 0; j < 2; j++) {
864
865         if (j == 0) {
866             size = Bytes_per_block;
867             max_cnt = xfer_size / Bytes_per_block;
868         } else {
869             /* 1KB - (Kb_per_block - 1) KB fragment */
870             size = xfer_size % Bytes_per_block;
871             max_cnt = 1;
872         }
873         if (size == 0)
874             continue;
875
876         args.count = size;
877         args.data.data_len = size;
878         args.data.data_val = buf;
879
880         /* check our stats to see if this would overflow */
881         if (!Timed_run) {
882             if (op_ptr->target_calls > 0) {
883                 if ((op_ptr->results.good_calls + max_cnt)
884                      > op_ptr->target_calls) {
885                     max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
886                 }
887             }
888         }
889
890         if (DEBUG_CHILD_RPC) {
891             (void) fprintf(stderr, "write: %d buffers\n", max_cnt);
892             (void) fflush(stderr);
893         }
894
895         /* make the call(s) now */
896         for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
897
898             if (DEBUG_CHILD_RPC) {
899 (void) fprintf(stderr, "%s: WRITE %s offset %u count %lu stable %d\n",
900 sfs_Myname, Cur_filename, args.offset._p._l, args.count, args.stable);
901                 (void) fflush(stderr);
902             }
903
904             /* capture length for possible dump */
905             Dump_length = fh_size(Cur_file_ptr);
906  
907             sfs_gettime(&start);
908             rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
909                                 xdr_WRITE3args, (char *) &args,
910                                 xdr_WRITE3res, (char *) &reply,
911                                 (Current_test_phase < Warmup_phase)
912                                      ? Nfs_timers[Init]
913                                      : Nfs_timers[op_ptr->call_class]);
914             sfs_gettime(&stop);
915             Cur_time = stop;
916
917             /* capture count and offset for possible dump */
918             Dump_count = args.data.data_len;
919             Dump_offset = args.offset._p._l;
920
921             if (rpc_stat == RPC_SUCCESS) {
922                 if (reply.status == NFS3_OK) {
923                     Cur_file_ptr->state = Exists;
924                     (void) memmove((char *) &Cur_file_ptr->attributes3,
925                                 (char *) &reply.resok.file_wcc.after.attr,
926                                 sizeof (Cur_file_ptr->attributes3));
927                     Cur_file_ptr->size = fh_size(Cur_file_ptr);
928                     args.offset._p._l += size;
929
930                     if (DEBUG_CHILD_RPC) {
931                         (void) fprintf(stderr, "%s: WRITE %s %d bytes\n",
932                                            sfs_Myname, Cur_filename, size);
933                         (void) fflush(stderr);
934                     }
935                 } else {
936                     if (DEBUG_CHILD_ERROR) {
937                          (void) fprintf(stderr,
938                                 "%s: write call NFS error %s on file %d\n",
939                                 sfs_Myname, nfs3_strerror(reply.status),
940                                 Cur_file_ptr->unique_num);
941                     }
942                 }
943                 sfs_elapsedtime(op_ptr, &start, &stop);
944                 op_ptr->results.good_calls++;
945                 Ops[TOTAL].results.good_calls++;
946                 ret++;
947             } else {
948                 if (DEBUG_CHILD_ERROR) {
949                      (void) fprintf(stderr,
950                                 "%s: write call RPC error %d on file %d\n",
951                             sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
952                 }
953                 op_ptr->results.bad_calls++;
954                 Ops[TOTAL].results.bad_calls++;
955             }
956         } /* for writing max_cnt packets */
957     } /* for buffers and fragments */
958
959     /*
960      * If we have not gotten an error and we were asked for an async write
961      * send a commit operation.
962      */
963     if (ret && stab_flag != FILE_SYNC)
964         ret += op_commit();
965
966     return(ret);
967
968 } /* op_write */
969
970
971 static int
972 op_create(void)
973 {
974     sfs_op_type         *op_ptr;                /* per operation info */
975     CREATE3args         args;
976     CREATE3res          reply;                  /* the reply */
977     enum clnt_stat      rpc_stat;               /* result from RPC call */
978     struct ladtime      start;
979     struct ladtime      stop;
980     int                 ret;                    /* ret val == call success */
981
982     op_ptr = &Ops[CREATE];
983     ret = 0;
984
985     /* set up the arguments */
986     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
987                 sizeof (nfs_fh3));
988     args.where.name = Cur_filename;
989     args.how.mode = UNCHECKED;
990     args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
991     args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
992     args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
993     args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
994     args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
995     args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
996     args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
997     args.how.createhow3_u.obj_attributes.atime.atime.seconds = Cur_time.esec;
998     args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
999                                                 Cur_time.usec * 1000;
1000     args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
1001     args.how.createhow3_u.obj_attributes.mtime.mtime.seconds = Cur_time.esec;
1002     args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
1003                                                 Cur_time.usec * 1000;
1004     args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
1005     args.how.createhow3_u.obj_attributes.size.size._p._u = (uint32_t) 0;
1006     args.how.createhow3_u.obj_attributes.size.size._p._l = (uint32_t) 0;
1007
1008     /* make the call now */
1009     sfs_gettime(&start);
1010     rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
1011                         xdr_CREATE3args, (char *) &args,
1012                         xdr_CREATE3res, (char *) &reply,
1013                         (Current_test_phase < Warmup_phase)
1014                                  ? Nfs_timers[Init]
1015                                  : Nfs_timers[op_ptr->call_class]);
1016     sfs_gettime(&stop);
1017     Cur_time = stop;
1018
1019     if (rpc_stat == RPC_SUCCESS) {
1020         if (reply.status == NFS3_OK) {
1021             Cur_file_ptr->state = Exists;
1022             (void) memmove((char *) &Cur_file_ptr->fh3,
1023                         (char *) &reply.resok.obj.handle,
1024                         sizeof (nfs_fh3));
1025             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1026             (void) memmove((char *) &Cur_file_ptr->attributes3,
1027                         (char *) &reply.resok.obj_attributes.attr,
1028                         sizeof(Cur_file_ptr->attributes3));
1029             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1030         } else {
1031             if (DEBUG_CHILD_ERROR) {
1032                  (void) fprintf(stderr,
1033                         "%s: create call NFS error %s on file %d\n",
1034                         sfs_Myname, nfs3_strerror(reply.status),
1035                         Cur_file_ptr->unique_num);
1036             }
1037         }
1038         sfs_elapsedtime(op_ptr, &start, &stop);
1039         op_ptr->results.good_calls++;
1040         Ops[TOTAL].results.good_calls++;
1041         ret++;
1042     } else {
1043         if (DEBUG_CHILD_ERROR) {
1044              (void) fprintf(stderr, "%s: create call RPC error %d on file %d\n",
1045                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1046         }
1047         op_ptr->results.bad_calls++;
1048         Ops[TOTAL].results.bad_calls++;
1049     }
1050     return(ret);
1051
1052 } /* op_create */
1053
1054
1055 static int
1056 op_mkdir(void)
1057 {
1058     sfs_op_type         *op_ptr;                /* per operation info */
1059     MKDIR3args          args;
1060     MKDIR3res           reply;                  /* the reply */
1061     enum clnt_stat      rpc_stat;               /* result from RPC call */
1062     struct ladtime      start;
1063     struct ladtime      stop;
1064     int                 ret;                    /* ret val == call success */
1065
1066     op_ptr = &Ops[MKDIR];
1067     ret = 0;
1068
1069     /* set up the arguments */
1070     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
1071                 sizeof (nfs_fh3));
1072     args.where.name = Cur_filename;
1073     args.attributes.mode.set_it = TRUE;
1074     args.attributes.mode.mode = (NFSMODE_DIR | 0777);
1075     args.attributes.uid.set_it = TRUE;
1076     args.attributes.uid.uid = Cur_uid;
1077     args.attributes.gid.set_it = TRUE;
1078     args.attributes.gid.gid = Cur_gid;
1079     args.attributes.size.set_it = TRUE;
1080     args.attributes.size.size._p._u = 0;
1081     args.attributes.size.size._p._l = 512;
1082     args.attributes.atime.set_it = TRUE;
1083     args.attributes.atime.atime.seconds = Cur_time.esec;
1084     args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
1085     args.attributes.mtime.set_it = TRUE;
1086     args.attributes.mtime.mtime.seconds = Cur_time.esec;
1087     args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
1088
1089     /* make the call now */
1090     sfs_gettime(&start);
1091     rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
1092                         xdr_MKDIR3args, (char *) &args,
1093                         xdr_MKDIR3res, (char *) &reply,
1094                         (Current_test_phase < Warmup_phase)
1095                                  ? Nfs_timers[Init]
1096                                  : Nfs_timers[op_ptr->call_class]);
1097     sfs_gettime(&stop);
1098     Cur_time = stop;
1099
1100     if (rpc_stat == RPC_SUCCESS) {
1101         if (reply.status == NFS3_OK) {
1102             Cur_file_ptr->state = Empty_dir;
1103             (void) memmove((char *) &Cur_file_ptr->fh3,
1104                         (char *) &reply.resok.obj.handle,
1105                         sizeof (nfs_fh3));
1106             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1107             (void) memmove((char *) &Cur_file_ptr->attributes3,
1108                         (char *) &reply.resok.obj_attributes.attr,
1109                         sizeof(Cur_file_ptr->attributes3));
1110             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1111         } else {
1112             if (DEBUG_CHILD_ERROR) {
1113                  (void) fprintf(stderr,
1114                         "%s: mkdir call NFS error %s on file %d\n",
1115                         sfs_Myname, nfs3_strerror(reply.status),
1116                         Cur_file_ptr->unique_num);
1117             }
1118         }
1119         sfs_elapsedtime(op_ptr, &start, &stop);
1120         op_ptr->results.good_calls++;
1121         Ops[TOTAL].results.good_calls++;
1122         ret++;
1123     } else {
1124         if (DEBUG_CHILD_ERROR) {
1125              (void) fprintf(stderr, "%s: mkdir call RPC error %d on file %d\n",
1126                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1127         }
1128         op_ptr->results.bad_calls++;
1129         Ops[TOTAL].results.bad_calls++;
1130     }
1131     return(ret);
1132
1133 } /* op_mkdir */
1134
1135
1136 static int
1137 op_symlink(void)
1138 {
1139     sfs_op_type         *op_ptr;                /* per operation info */
1140     sfs_fh_type         *target_fileinfo_ptr;   /* target file */
1141     SYMLINK3args        args;
1142     SYMLINK3res         reply;                  /* the reply */
1143     char                sym_data[NFS_MAXPATHLEN];       /* symlink data */
1144     enum clnt_stat      rpc_stat;               /* result from RPC call */
1145     struct ladtime      start;
1146     struct ladtime      stop;
1147     int                 ret;                    /* ret val == call success */
1148
1149     op_ptr = &Ops[SYMLINK];
1150     ret = 0;
1151
1152     /* set up the arguments */
1153     target_fileinfo_ptr = randfh(SYMLINK, 0, 0, Exists, Sfs_non_io_file);
1154     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
1155                 sizeof (nfs_fh3));
1156     args.where.name = Cur_filename;
1157
1158     (void) strcpy(sym_data, "./");
1159     (void) strcat(sym_data, target_fileinfo_ptr->file_name);
1160     args.symlink.symlink_attributes.size.set_it = TRUE;
1161     args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
1162     args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
1163     args.symlink.symlink_data = sym_data;
1164
1165     args.symlink.symlink_attributes.mode.set_it = TRUE;
1166     args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
1167     args.symlink.symlink_attributes.uid.set_it = TRUE;
1168     args.symlink.symlink_attributes.uid.uid = Cur_uid;
1169     args.symlink.symlink_attributes.gid.set_it = TRUE;
1170     args.symlink.symlink_attributes.gid.gid = Cur_gid;
1171     args.symlink.symlink_attributes.atime.set_it = TRUE;
1172     args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
1173     args.symlink.symlink_attributes.atime.atime.nseconds =
1174                                                 Cur_time.usec * 1000;
1175     args.symlink.symlink_attributes.mtime.set_it = TRUE;
1176     args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
1177     args.symlink.symlink_attributes.mtime.mtime.nseconds =
1178                                                 Cur_time.usec * 1000;
1179
1180     /* make the call now */
1181     sfs_gettime(&start);
1182     rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
1183                         xdr_SYMLINK3args, (char *) &args,
1184                         xdr_SYMLINK3res, (char *) &reply,
1185                         ((int)Current_test_phase < (int)Warmup_phase)
1186                                  ? Nfs_timers[Init]
1187                                  : Nfs_timers[op_ptr->call_class]);
1188     sfs_gettime(&stop);
1189     Cur_time = stop;
1190
1191     if (rpc_stat == RPC_SUCCESS) {
1192         if (reply.status == NFS3_OK) {
1193             /*
1194              * SYMLINK doesn't return a fh. If we try to access this symlink
1195              * (eg, remove(), readlink()) before we do a lookup, we won't have
1196              * a fh to use. So, we do a lookup call here. If it fails, we fill
1197              * in what we can.
1198              */
1199             Cur_file_ptr->state = Exists;
1200             if (op_lookup() == 0) {
1201                 (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1202                 Cur_file_ptr->attributes3.type = NF3LNK;
1203                 Cur_file_ptr->attributes3.mode = (NFSMODE_LNK|0777);
1204                 Cur_file_ptr->attributes3.uid = Cur_uid;
1205                 Cur_file_ptr->attributes3.gid = Cur_gid;
1206                 Cur_file_ptr->attributes3.atime.seconds = Cur_time.esec;
1207                 Cur_file_ptr->attributes3.atime.nseconds =
1208                                                         Cur_time.usec * 1000;
1209                 Cur_file_ptr->attributes3.mtime =
1210                         Cur_file_ptr->attributes3.atime;
1211             } else
1212                 ret++;
1213         } else {
1214             if (DEBUG_CHILD_ERROR) {
1215                  (void) fprintf(stderr,
1216                         "%s: symlink call NFS error %s on file %d\n",
1217                         sfs_Myname, nfs3_strerror(reply.status),
1218                         Cur_file_ptr->unique_num);
1219             }
1220         }
1221         sfs_elapsedtime(op_ptr, &start, &stop);
1222         op_ptr->results.good_calls++;
1223         Ops[TOTAL].results.good_calls++;
1224         ret++;
1225     } else {
1226         if (DEBUG_CHILD_ERROR) {
1227              (void) fprintf(stderr,
1228                         "%s: symlink call RPC error %d on file %d\n",
1229                         sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1230         }
1231         op_ptr->results.bad_calls++;
1232         Ops[TOTAL].results.bad_calls++;
1233     }
1234     return(ret);
1235
1236 } /* op_symlink */
1237
1238
1239 static int
1240 op_mknod(void)
1241 {
1242     sfs_op_type         *op_ptr;                /* per operation info */
1243     MKNOD3args          args;
1244     MKNOD3res           reply;
1245     enum clnt_stat      rpc_stat;               /* result from RPC call */
1246     struct ladtime      start;
1247     struct ladtime      stop;
1248     int                 ret;                    /* ret val == call success */
1249
1250     op_ptr = &Ops[MKNOD];
1251     ret = 0;
1252
1253     /* set up the arguments */
1254     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh3,
1255                 sizeof (nfs_fh3));
1256     args.where.name = Cur_filename;
1257     args.what.type = NF3FIFO;
1258     args.what.mknoddata3_u.pipe_attributes.mode.set_it = TRUE;
1259     args.what.mknoddata3_u.pipe_attributes.mode.mode = (NFSMODE_FIFO | 0777);
1260     args.what.mknoddata3_u.pipe_attributes.uid.set_it = TRUE;
1261     args.what.mknoddata3_u.pipe_attributes.uid.uid = Cur_uid;
1262     args.what.mknoddata3_u.pipe_attributes.gid.set_it = TRUE;
1263     args.what.mknoddata3_u.pipe_attributes.gid.gid = Cur_gid;
1264     args.what.mknoddata3_u.pipe_attributes.size.set_it = TRUE;
1265     args.what.mknoddata3_u.pipe_attributes.size.size._p._u = (uint32_t) 0;
1266     args.what.mknoddata3_u.pipe_attributes.size.size._p._l =
1267                                                         (uint32_t) 512;
1268     args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
1269     args.what.mknoddata3_u.pipe_attributes.atime.atime.seconds =
1270                                                         Cur_time.esec;
1271     args.what.mknoddata3_u.pipe_attributes.atime.atime.nseconds =
1272                                                         Cur_time.usec * 1000;
1273     args.what.mknoddata3_u.pipe_attributes.atime.set_it = TRUE;
1274     args.what.mknoddata3_u.pipe_attributes.mtime.mtime.seconds =
1275                                                                 Cur_time.esec;
1276     args.what.mknoddata3_u.pipe_attributes.mtime.mtime.nseconds =
1277                                                         Cur_time.usec * 1000;
1278
1279     /* make the call now */
1280     sfs_gettime(&start);
1281     rpc_stat = clnt_call(NFS_client, NFSPROC3_MKNOD,
1282                         xdr_MKNOD3args, (char *) &args,
1283                         xdr_MKNOD3res, (char *) &reply,
1284                         (Current_test_phase < Warmup_phase)
1285                                  ? Nfs_timers[Init]
1286                                  : Nfs_timers[op_ptr->call_class]);
1287     sfs_gettime(&stop);
1288     Cur_time = stop;
1289
1290     if (rpc_stat == RPC_SUCCESS) {
1291         if (reply.status == NFS3_OK) {
1292             Cur_file_ptr->state = Exists;
1293             (void) memmove((char *) &Cur_file_ptr->fh3,
1294                         (char *) &reply.resok.obj.handle,
1295                         sizeof (nfs_fh3));
1296             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1297             (void) memmove((char *) &Cur_file_ptr->attributes3,
1298                         (char *) &reply.resok.obj_attributes.attr,
1299                         sizeof(Cur_file_ptr->attributes3));
1300             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1301         } else {
1302             if (DEBUG_CHILD_ERROR) {
1303                  (void) fprintf(stderr,
1304                         "%s: mknod call NFS error %s on file %d\n",
1305                         sfs_Myname, nfs3_strerror(reply.status),
1306                         Cur_file_ptr->unique_num);
1307             }
1308         }
1309         sfs_elapsedtime(op_ptr, &start, &stop);
1310         op_ptr->results.good_calls++;
1311         Ops[TOTAL].results.good_calls++;
1312         ret++;
1313     } else {
1314         if (DEBUG_CHILD_ERROR) {
1315              (void) fprintf(stderr, "%s: mknod call RPC error %d on file %d\n",
1316                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1317         }
1318         op_ptr->results.bad_calls++;
1319         Ops[TOTAL].results.bad_calls++;
1320     }
1321     return(ret);
1322
1323 } /* op_mknod */
1324
1325
1326 static int
1327 op_remove(void)
1328 {
1329     sfs_op_type         *op_ptr;        /* per operation info */
1330     REMOVE3args         args;
1331     REMOVE3res          reply;          /* the reply */
1332     enum clnt_stat      rpc_stat;       /* result from RPC call */
1333     struct ladtime      start;
1334     struct ladtime      stop;
1335     int                 ret;            /* ret val == call success */
1336
1337     op_ptr = &Ops[REMOVE];
1338     ret = 0;
1339
1340     /* set up the arguments */
1341     args.object.name = Cur_filename;
1342     (void) memmove((char *) &args.object.dir,(char *) &Cur_file_ptr->dir->fh3,
1343                 sizeof (nfs_fh3));
1344
1345     /* make the call now */
1346     sfs_gettime(&start);
1347     rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
1348                         xdr_REMOVE3args, (char *) &args,
1349                         xdr_REMOVE3res, (char *) &reply,
1350                         (Current_test_phase < Warmup_phase)
1351                                  ? Nfs_timers[Init]
1352                                  : Nfs_timers[op_ptr->call_class]);
1353     sfs_gettime(&stop);
1354     Cur_time = stop;
1355
1356     if (rpc_stat == RPC_SUCCESS) {
1357         if (reply.status == NFS3_OK) {
1358             Cur_file_ptr->state = Nonexistent;
1359         } else {
1360             if (DEBUG_CHILD_ERROR) {
1361                  (void) fprintf(stderr,
1362                                 "%s: remove call NFS error %s on file %d\n",
1363                                 sfs_Myname, nfs3_strerror(reply.status),
1364                                 Cur_file_ptr->unique_num);
1365             }
1366         }
1367         sfs_elapsedtime(op_ptr, &start, &stop);
1368         op_ptr->results.good_calls++;
1369         Ops[TOTAL].results.good_calls++;
1370         ret++;
1371     } else {
1372         if (DEBUG_CHILD_ERROR) {
1373              (void) fprintf(stderr, "%s: remove call RPC error %d on file %d\n",
1374                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1375         }
1376         op_ptr->results.bad_calls++;
1377         Ops[TOTAL].results.bad_calls++;
1378     }
1379     return(ret);
1380
1381 } /* op_remove */
1382
1383
1384 static int
1385 op_rmdir(void)
1386 {
1387     sfs_op_type         *op_ptr;        /* per operation info */
1388     RMDIR3args          args;
1389     RMDIR3res           reply;          /* the reply */
1390     enum clnt_stat      rpc_stat;       /* result from RPC call */
1391     struct ladtime      start;
1392     struct ladtime      stop;
1393     int                 ret;            /* ret val == call success */
1394
1395     op_ptr = &Ops[RMDIR];
1396     ret = 0;
1397
1398     /* set up the arguments */
1399     (void) memmove((char *) &args.object.dir, (char *) &Cur_file_ptr->dir->fh3,
1400                 sizeof (nfs_fh3));
1401     args.object.name = Cur_file_ptr->file_name;
1402
1403     /* make the call now */
1404     sfs_gettime(&start);
1405     rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
1406                         xdr_RMDIR3args, (char *) &args,
1407                         xdr_RMDIR3res, (char *) &reply,
1408                         (Current_test_phase < Warmup_phase)
1409                                  ? Nfs_timers[Init]
1410                                  : Nfs_timers[op_ptr->call_class]);
1411     sfs_gettime(&stop);
1412     Cur_time = stop;
1413
1414     if (rpc_stat == RPC_SUCCESS) {
1415         if (reply.status == NFS3_OK) {
1416             Cur_file_ptr->state = Nonexistent;
1417         } else {
1418             if (DEBUG_CHILD_ERROR) {
1419                  (void) fprintf(stderr,
1420                                 "%s: rmdir call NFS error %s on file %d\n",
1421                                 sfs_Myname, nfs3_strerror(reply.status),
1422                                 Cur_file_ptr->unique_num);
1423             }
1424         }
1425         sfs_elapsedtime(op_ptr, &start, &stop);
1426         op_ptr->results.good_calls++;
1427         Ops[TOTAL].results.good_calls++;
1428         ret++;
1429     } else {
1430         if (DEBUG_CHILD_ERROR) {
1431              (void) fprintf(stderr, "%s: rmdir call RPC error %d on file %d\n",
1432                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1433         }
1434         op_ptr->results.bad_calls++;
1435         Ops[TOTAL].results.bad_calls++;
1436     }
1437     return(ret);
1438
1439 } /* op_rmdir */
1440
1441
1442 static int
1443 op_rename(void)
1444 {
1445     sfs_op_type         *op_ptr;                /* per operation info */
1446     sfs_fh_type         *target_fileinfo_ptr;   /* target name */
1447     RENAME3args         args;
1448     RENAME3res          reply;                  /* the reply */
1449     enum clnt_stat      rpc_stat;               /* result from RPC call */
1450     struct ladtime      start;
1451     struct ladtime      stop;
1452     int                 ret;                    /* ret val == call success */
1453
1454     op_ptr = &Ops[RENAME];
1455     ret = 0;
1456
1457     /* set up the arguments */
1458     (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh3,
1459                 sizeof (nfs_fh3));
1460     (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh3,
1461                 sizeof (nfs_fh3));
1462
1463     target_fileinfo_ptr = randfh(RENAME, 0, 0, Nonexistent,
1464                                  Sfs_non_io_file);
1465
1466     args.from.name = Cur_file_ptr->file_name;
1467     (void) sprintf(target_fileinfo_ptr->file_name, Filespec,
1468                    target_fileinfo_ptr->unique_num);
1469     args.to.name = target_fileinfo_ptr->file_name;
1470
1471     /* make the call now */
1472     sfs_gettime(&start);
1473     rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
1474                         xdr_RENAME3args, (char *) &args,
1475                         xdr_RENAME3res, (char *) &reply,
1476                         (Current_test_phase < Warmup_phase)
1477                                  ? Nfs_timers[Init]
1478                                  : Nfs_timers[op_ptr->call_class]);
1479     sfs_gettime(&stop);
1480     Cur_time = stop;
1481
1482     if (rpc_stat == RPC_SUCCESS) {
1483         if (reply.status == NFS3_OK) {
1484             target_fileinfo_ptr->state = Exists;
1485             (void) memmove((char *) &target_fileinfo_ptr->fh3,
1486                         (char *) &Cur_file_ptr->fh3,
1487                         sizeof (nfs_fh3));
1488             target_fileinfo_ptr->attributes3 = Cur_file_ptr->attributes3;
1489             target_fileinfo_ptr->size = fh_size(Cur_file_ptr);
1490             Cur_file_ptr->state = Nonexistent;
1491         } else {
1492             if (DEBUG_CHILD_ERROR) {
1493                  (void) fprintf(stderr,
1494                         "%s: rename call NFS error %s on file %d\n",
1495                         sfs_Myname, nfs3_strerror(reply.status),
1496                         Cur_file_ptr->unique_num);
1497             }
1498         }
1499         sfs_elapsedtime(op_ptr, &start, &stop);
1500         op_ptr->results.good_calls++;
1501         Ops[TOTAL].results.good_calls++;
1502         ret++;
1503     } else {
1504         if (DEBUG_CHILD_ERROR) {
1505              (void) fprintf(stderr, "%s: rename call RPC error %d on file %d\n",
1506                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1507         }
1508         op_ptr->results.bad_calls++;
1509         Ops[TOTAL].results.bad_calls++;
1510     }
1511     return(ret);
1512
1513 } /* op_rename */
1514
1515
1516 static int
1517 op_link(void)
1518 {
1519     sfs_op_type         *op_ptr;                /* per operation info */
1520     sfs_fh_type         *target_fileinfo_ptr;   /* target */
1521     LINK3args           args;
1522     LINK3res            reply;                  /* the reply */
1523     enum clnt_stat      rpc_stat;               /* result from RPC call */
1524     struct ladtime      start;
1525     struct ladtime      stop;
1526     int                 ret;                    /* ret val == call success */
1527
1528     op_ptr = &Ops[LINK];
1529     ret = 0;
1530
1531     /* set up the arguments */
1532     target_fileinfo_ptr = randfh(LINK, 0, 0, Exists, Sfs_non_io_file);
1533     (void) memmove((char *) &args.file, (char *) &target_fileinfo_ptr->fh3,
1534                 sizeof (nfs_fh3));
1535     (void) memmove((char *) &args.link.dir, (char *) &Cur_file_ptr->dir->fh3,
1536                 sizeof (nfs_fh3));
1537     args.link.name = Cur_filename;
1538
1539     /* make the call now */
1540     sfs_gettime(&start);
1541     rpc_stat = clnt_call(NFS_client, NFSPROC3_LINK,
1542                         xdr_LINK3args, (char *) &args,
1543                         xdr_LINK3res, (char *) &reply,
1544                         (Current_test_phase < Warmup_phase)
1545                                  ? Nfs_timers[Init]
1546                                  : Nfs_timers[op_ptr->call_class]);
1547     sfs_gettime(&stop);
1548     Cur_time = stop;
1549
1550     if (rpc_stat == RPC_SUCCESS) {
1551         if (reply.status == NFS3_OK) {
1552             Cur_file_ptr->state = Exists;
1553             (void) memmove((char *) &Cur_file_ptr->fh3,
1554                         (char *) &target_fileinfo_ptr->fh3,
1555                         sizeof (nfs_fh3));
1556             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1557             target_fileinfo_ptr->attributes3.nlink++;
1558             Cur_file_ptr->attributes3 = target_fileinfo_ptr->attributes3;
1559             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1560         } else {
1561             if (DEBUG_CHILD_ERROR) {
1562                  (void) fprintf(stderr,
1563                         "%s: link call NFS error %s on file %d\n",
1564                         sfs_Myname, nfs3_strerror(reply.status),
1565                         Cur_file_ptr->unique_num);
1566             }
1567         }
1568         sfs_elapsedtime(op_ptr, &start, &stop);
1569         op_ptr->results.good_calls++;
1570         Ops[TOTAL].results.good_calls++;
1571         ret++;
1572     } else {
1573         if (DEBUG_CHILD_ERROR) {
1574              (void) fprintf(stderr, "%s: link call RPC error %d on file %d\n",
1575                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1576         }
1577         op_ptr->results.bad_calls++;
1578         Ops[TOTAL].results.bad_calls++;
1579     }
1580     return(ret);
1581
1582 } /* op_link */
1583
1584
1585 static int
1586 op_readdir(void)
1587 {
1588     sfs_op_type         *op_ptr;                /* per operation info */
1589     READDIR3args        args;
1590     READDIR3res         reply;                  /* the reply */
1591     enum clnt_stat      rpc_stat;               /* result from RPC call */
1592     int                 i;
1593     struct ladtime      start;
1594     struct ladtime      stop;
1595     int                 ret;                    /* ret val == call success */
1596     bool_t              hit_eof;
1597         /* array of entries */
1598     entry3              entry_stream[SFS_MAXDIRENTS];
1599     entry3              *entries;               /* ptr to the dir entry */
1600
1601     op_ptr = &Ops[READDIR];
1602     ret = 0;
1603
1604     /* set up the arguments */
1605     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
1606                 sizeof (nfs_fh3));
1607     args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
1608     (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
1609     args.count = DEFAULT_MAX_BUFSIZE;
1610
1611     /* Have lower layers fill in the data directly.  */
1612     (void) memset((char *) &reply, '\0', sizeof (reply));
1613     (void) memset((char *) entry_stream, '\0',
1614                                         sizeof (entry3) * SFS_MAXDIRENTS);
1615     reply.resok.count = SFS_MAXDIRENTS;
1616     reply.resok.reply.entries = entry_stream;
1617
1618     /* make the call now */
1619     sfs_gettime(&start);
1620     rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIR,
1621                         xdr_READDIR3args, (char *) &args,
1622                         xdr_READDIR3res, (char *) &reply,
1623                         (Current_test_phase < Warmup_phase)
1624                                  ? Nfs_timers[Init]
1625                                  : Nfs_timers[op_ptr->call_class]);
1626     sfs_gettime(&stop);
1627     Cur_time = stop;
1628
1629     if (rpc_stat == RPC_SUCCESS) {
1630         if (reply.status == NFS3_OK) {
1631
1632             if (DEBUG_CHILD_RPC) {
1633                 hit_eof = reply.resok.reply.eof;
1634                 entries = reply.resok.reply.entries;
1635                 for (i = 0; i < reply.resok.count; i++) {
1636                     (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
1637                                     sfs_Myname, hit_eof, entries[i].name);
1638                 }
1639                 (void) fflush(stderr);
1640             }
1641         } else {
1642             if (DEBUG_CHILD_ERROR) {
1643                  (void) fprintf(stderr,
1644                         "%s: readdir call NFS error %s on file %d\n",
1645                         sfs_Myname, nfs3_strerror(reply.status),
1646                         Cur_file_ptr->unique_num);
1647             }
1648         }
1649         sfs_elapsedtime(op_ptr, &start, &stop);
1650         op_ptr->results.good_calls++;
1651         Ops[TOTAL].results.good_calls++;
1652         ret++;
1653     } else {
1654         if (DEBUG_CHILD_ERROR) {
1655              (void) fprintf(stderr,
1656                                 "%s: readdir call RPC error %d on file %d\n",
1657                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1658         }
1659         op_ptr->results.bad_calls++;
1660         Ops[TOTAL].results.bad_calls++;
1661     }
1662     return(ret);
1663
1664 } /* op_readdir */
1665
1666
1667 static int
1668 op_readdirplus(void)
1669 {
1670     sfs_op_type         *op_ptr;                /* per operation info */
1671     READDIRPLUS3args    args;
1672     READDIRPLUS3res     reply;                  /* the reply */
1673     enum clnt_stat      rpc_stat;               /* result from RPC call */
1674     int                 i;
1675     struct ladtime      start;
1676     struct ladtime      stop;
1677     int                 ret;                    /* ret val == call success */
1678     bool_t              hit_eof;
1679         /* array of entries */
1680     entryplus3          entry_stream[SFS_MAXDIRENTS];
1681     entryplus3          *entries;
1682
1683     op_ptr = &Ops[READDIRPLUS];
1684     ret = 0;
1685
1686     /* set up the arguments */
1687     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh3,
1688                 sizeof (nfs_fh3));
1689     args.cookie._p._l = args.cookie._p._u = (uint32_t) 0;
1690     (void) memset((char *) args.cookieverf, '\0', NFS3_COOKIEVERFSIZE);
1691     (void) memset((char *) entry_stream, '\0',
1692                                 sizeof (entryplus3) * SFS_MAXDIRENTS);
1693     args.dircount = DEFAULT_MAX_BUFSIZE;
1694     args.maxcount = DEFAULT_MAX_BUFSIZE;
1695
1696     /* Have lower layers fill in the data directly.  */
1697     reply.resok.count = SFS_MAXDIRENTS;
1698     reply.resok.reply.entries = entry_stream;
1699
1700     /* make the call now */
1701     sfs_gettime(&start);
1702     rpc_stat = clnt_call(NFS_client, NFSPROC3_READDIRPLUS,
1703                         xdr_READDIRPLUS3args, (char *) &args,
1704                         xdr_READDIRPLUS3res, (char *) &reply,
1705                         (Current_test_phase < Warmup_phase)
1706                                  ? Nfs_timers[Init]
1707                                  : Nfs_timers[op_ptr->call_class]);
1708     sfs_gettime(&stop);
1709     Cur_time = stop;
1710
1711     if (rpc_stat == RPC_SUCCESS) {
1712         if (reply.status == NFS3_OK) {
1713
1714             if (DEBUG_CHILD_RPC) {
1715                 hit_eof = reply.resok.reply.eof;
1716                 entries = reply.resok.reply.entries;
1717                 for (i = 0; i < reply.resok.count; i++) {
1718                     (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
1719                                     sfs_Myname, hit_eof, entries[i].name);
1720                 }
1721                 (void) fflush(stderr);
1722             }
1723         } else {
1724             if (DEBUG_CHILD_ERROR) {
1725                  (void) fprintf(stderr,
1726                         "%s: readdir call NFS error %s on file %d\n",
1727                         sfs_Myname, nfs3_strerror(reply.status),
1728                         Cur_file_ptr->unique_num);
1729             }
1730         }
1731         sfs_elapsedtime(op_ptr, &start, &stop);
1732         op_ptr->results.good_calls++;
1733         Ops[TOTAL].results.good_calls++;
1734         ret++;
1735     } else {
1736         if (DEBUG_CHILD_ERROR) {
1737              (void) fprintf(stderr,
1738                                 "%s: readdir call RPC error %d on file %d\n",
1739                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1740         }
1741         op_ptr->results.bad_calls++;
1742         Ops[TOTAL].results.bad_calls++;
1743     }
1744     return(ret);
1745
1746 } /* op_readdirplus */
1747
1748
1749 static int
1750 op_fsstat(void)
1751 {
1752     sfs_op_type         *op_ptr;        /* per operation info */
1753     FSSTAT3args         args;
1754     FSSTAT3res          reply;          /* the reply */
1755     enum clnt_stat      rpc_stat;       /* result from RPC call */
1756     struct ladtime      start;
1757     struct ladtime      stop;
1758     int                 ret;            /* ret val == call success */
1759
1760     op_ptr = &Ops[FSSTAT];
1761     ret = 0;
1762
1763     /* set up the arguments */
1764     (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
1765                 sizeof (nfs_fh3));
1766
1767     /* make the call */
1768     sfs_gettime(&start);
1769     rpc_stat = clnt_call(NFS_client, NFSPROC3_FSSTAT,
1770                         xdr_FSSTAT3args, (char *) &args,
1771                         xdr_FSSTAT3args, (char *) &reply,
1772                         (Current_test_phase < Warmup_phase)
1773                                  ? Nfs_timers[Init]
1774                                  : Nfs_timers[op_ptr->call_class]);
1775     sfs_gettime(&stop);
1776     Cur_time = stop;
1777
1778     if (rpc_stat == RPC_SUCCESS) {
1779         sfs_elapsedtime(op_ptr, &start, &stop);
1780         op_ptr->results.good_calls++;
1781         Ops[TOTAL].results.good_calls++;
1782         ret++;
1783     } else {
1784         if (DEBUG_CHILD_ERROR) {
1785              (void) fprintf(stderr, "%s: fsstat call RPC error %d\n",
1786                                                 sfs_Myname, rpc_stat);
1787         }
1788         op_ptr->results.bad_calls++;
1789         Ops[TOTAL].results.bad_calls++;
1790     }
1791     return(ret);
1792
1793 } /* op_fsstat */
1794
1795
1796 static int
1797 op_fsinfo(void)
1798 {
1799     sfs_op_type         *op_ptr;        /* per operation info */
1800     FSINFO3args         args;
1801     FSINFO3res          reply;          /* the reply */
1802     enum clnt_stat      rpc_stat;       /* result from RPC call */
1803     struct ladtime      start;
1804     struct ladtime      stop;
1805     int                 ret;            /* ret val == call success */
1806
1807     op_ptr = &Ops[FSINFO];
1808     ret = 0;
1809
1810     /* set up the arguments */
1811     (void) memmove((char *) &args.fsroot, (char *) &Cur_file_ptr->dir->fh3,
1812                 sizeof (nfs_fh3));
1813
1814     /* make the call */
1815     sfs_gettime(&start);
1816     rpc_stat = clnt_call(NFS_client, NFSPROC3_FSINFO,
1817                         xdr_FSINFO3args, (char *) &args,
1818                         xdr_FSINFO3args, (char *) &reply,
1819                         (Current_test_phase < Warmup_phase)
1820                                  ? Nfs_timers[Init]
1821                                  : Nfs_timers[op_ptr->call_class]);
1822     sfs_gettime(&stop);
1823     Cur_time = stop;
1824
1825     if (rpc_stat == RPC_SUCCESS) {
1826         sfs_elapsedtime(op_ptr, &start, &stop);
1827         op_ptr->results.good_calls++;
1828         Ops[TOTAL].results.good_calls++;
1829         ret++;
1830     } else {
1831         if (DEBUG_CHILD_ERROR) {
1832              (void) fprintf(stderr, "%s: fsinfo call RPC error %d\n",
1833                                                 sfs_Myname, rpc_stat);
1834         }
1835         op_ptr->results.bad_calls++;
1836         Ops[TOTAL].results.bad_calls++;
1837     }
1838     return(ret);
1839
1840 } /* op_fsinfo */
1841
1842
1843 static int
1844 op_pathconf(void)
1845 {
1846     sfs_op_type         *op_ptr;        /* per operation info */
1847     PATHCONF3args       args;
1848     PATHCONF3res        reply;          /* the reply */
1849     enum clnt_stat      rpc_stat;       /* result from RPC call */
1850     struct ladtime      start;
1851     struct ladtime      stop;
1852     int                 ret;            /* ret val == call success */
1853
1854     op_ptr = &Ops[PATHCONF];
1855     ret = 0;
1856
1857     /* set up the arguments */
1858     (void) memmove((char *) &args.object, (char *) &Cur_file_ptr->fh3,
1859                 sizeof (nfs_fh3));
1860
1861     /* make the call */
1862     sfs_gettime(&start);
1863     rpc_stat = clnt_call(NFS_client, NFSPROC3_PATHCONF,
1864                         xdr_PATHCONF3args, (char *) &args,
1865                         xdr_PATHCONF3args, (char *) &reply,
1866                         (Current_test_phase < Warmup_phase)
1867                                  ? Nfs_timers[Init]
1868                                  : Nfs_timers[op_ptr->call_class]);
1869     sfs_gettime(&stop);
1870     Cur_time = stop;
1871
1872     if (rpc_stat == RPC_SUCCESS) {
1873         sfs_elapsedtime(op_ptr, &start, &stop);
1874         op_ptr->results.good_calls++;
1875         Ops[TOTAL].results.good_calls++;
1876         ret++;
1877     } else {
1878         if (DEBUG_CHILD_ERROR) {
1879              (void) fprintf(stderr,
1880                         "%s: pathconf call RPC error %d on file %d\n",
1881                         sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1882         }
1883         op_ptr->results.bad_calls++;
1884         Ops[TOTAL].results.bad_calls++;
1885     }
1886     return(ret);
1887
1888 } /* op_pathconf */
1889
1890
1891 static int
1892 op_commit(void)
1893 {
1894     sfs_op_type                 *op_ptr;        /* per operation info */
1895     int32_t                     size;           /* size of data write */
1896     COMMIT3args                 args;
1897     COMMIT3res                  reply;          /* the reply */
1898     enum clnt_stat              rpc_stat;       /* result from RPC call */
1899     struct ladtime              start;
1900     struct ladtime              stop;
1901     int                         ret;            /* ret val == call success */
1902
1903     op_ptr = &Ops[COMMIT];
1904     ret = 0;
1905
1906     /* set up the arguments */
1907     (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh3,
1908                 sizeof (nfs_fh3));
1909     args.offset._p._u = args.offset._p._l = (uint32_t) 0;
1910     args.count = Cur_file_ptr->attributes3.size._p._l;
1911     size = args.count;
1912
1913     sfs_gettime(&start);
1914     rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
1915                                 xdr_COMMIT3args, (char *) &args,
1916                                 xdr_COMMIT3res, (char *) &reply,
1917                                 (Current_test_phase < Warmup_phase)
1918                                      ? Nfs_timers[Init]
1919                                      : Nfs_timers[op_ptr->call_class]);
1920     sfs_gettime(&stop);
1921     Cur_time = stop;
1922
1923     if (rpc_stat == RPC_SUCCESS) {
1924         if (reply.status == NFS3_OK) {
1925             Cur_file_ptr->state = Exists;
1926             (void) memmove((char *) &Cur_file_ptr->attributes3,
1927                         (char *) &reply.resok.file_wcc.after.attr,
1928                         sizeof(Cur_file_ptr->attributes3));
1929             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1930
1931             if (DEBUG_CHILD_RPC) {
1932                 (void) fprintf(stderr, "%s: WRITE %s %ld bytes\n",
1933                                            sfs_Myname, Cur_filename, size);
1934                 (void) fflush(stderr);
1935             }
1936         } else {
1937             if (DEBUG_CHILD_ERROR) {
1938                  (void) fprintf(stderr,
1939                         "%s: write call NFS error %s on file %d\n",
1940                         sfs_Myname, nfs3_strerror(reply.status),
1941                         Cur_file_ptr->unique_num);
1942             }
1943         }
1944         sfs_elapsedtime(op_ptr, &start, &stop);
1945         op_ptr->results.good_calls++;
1946         Ops[TOTAL].results.good_calls++;
1947         ret++;
1948     } else {
1949         if (DEBUG_CHILD_ERROR) {
1950              (void) fprintf(stderr, "%s: write call RPC error %d on file %d\n",
1951                             sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1952         }
1953         op_ptr->results.bad_calls++;
1954         Ops[TOTAL].results.bad_calls++;
1955     }
1956
1957     return(ret);
1958
1959 } /* op_commit */
1960
1961
1962 #define LAD_RETRIABLE(stat) (((stat) == RPC_TIMEDOUT) || ((stat) == RPC_CANTDECODERES))
1963
1964 /*
1965  * Reliably lookup a file in the current directory
1966  * Return:
1967  *      -1      RPC error
1968  *      1       File doesn't exist
1969  *      0       File exists
1970  */
1971 int
1972 lad_lookup(sfs_fh_type *file_ptr, char *name)
1973 {
1974     LOOKUP3args         args;
1975     LOOKUP3res          reply;          /* the reply */
1976     enum clnt_stat      rpc_stat;       /* result from RPC call */
1977
1978     if (DEBUG_CHILD_RPC) {
1979         (void) fprintf(stderr, "%s:lad_lookup: %lx[%lx] %s\n", sfs_Myname,
1980                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1981         (void) fflush(stderr);
1982     }
1983
1984     /* CONSTCOND */
1985     while (1) {
1986         /* set up the arguments */
1987         (void) memmove((char *) &args.what.dir, (char *) &file_ptr->dir->fh3,
1988                                                         sizeof (nfs_fh3));
1989         args.what.name = name;
1990         (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
1991
1992         /* make the call */
1993         rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
1994                         xdr_LOOKUP3args, (char *) &args,
1995                         xdr_LOOKUP3res, (char *) &reply,
1996                         Nfs_timers[Init]);
1997
1998         if (rpc_stat == RPC_SUCCESS) 
1999                 break;
2000         if (rpc_stat != RPC_TIMEDOUT) {
2001                 (void) fprintf(stderr, "lad_lookup(%s) RPC call failed : %s\n",
2002                                 name, clnt_sperrno(rpc_stat));
2003         }
2004         if (!LAD_RETRIABLE(rpc_stat)) {
2005                 return(-1);
2006         }
2007     }
2008
2009     if (reply.status == NFS3ERR_NOENT) {
2010         return(1);
2011     }
2012
2013     if (reply.status != NFS3_OK) {
2014         (void) fprintf(stderr, "lad_lookup(%s) NFS call failed : %s\n",
2015                         name, nfs3_strerror(reply.status));
2016         return(-1);
2017     }
2018
2019     file_ptr->state = Exists;
2020     (void) memmove((char *) &file_ptr->fh3,
2021                         (char *) &reply.resok.object,
2022                         sizeof (nfs_fh3));
2023     (void) strcpy(file_ptr->file_name, name);
2024     (void) memmove((char *) &file_ptr->attributes3,
2025                                 (char *) &reply.resok.obj_attributes.attr,
2026                                 sizeof (file_ptr->attributes3));
2027     file_ptr->size = fh_size(file_ptr);
2028     return(0);
2029 }
2030
2031 /*
2032  * Reliably remove a file in the current directory
2033  */
2034 int
2035 lad_remove(sfs_fh_type *file_ptr, char *name)
2036 {
2037     REMOVE3args         args;
2038     REMOVE3res          reply;          /* the reply */
2039     enum clnt_stat      rpc_stat;       /* result from RPC call */
2040     int                 retried = 0;
2041
2042     /*
2043      * This function presumes that the file name does exist
2044      */
2045     if (file_ptr->attributes3.type == NF3DIR)
2046         return (lad_rmdir(file_ptr, name));
2047
2048     if (DEBUG_CHILD_RPC) {
2049         (void) fprintf(stderr, "%s:lad_remove: %lx[%lx] %s\n", sfs_Myname,
2050                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
2051         (void) fflush(stderr);
2052     }
2053
2054     /* CONSTCOND */
2055     while (1) {
2056         /* set up the arguments */
2057         args.object.name = name;
2058         (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
2059                         sizeof(nfs_fh3));
2060
2061         /* make the call now */
2062         rpc_stat = clnt_call(NFS_client, NFSPROC3_REMOVE,
2063                         xdr_REMOVE3args, (char *) &args,
2064                         xdr_REMOVE3res, (char *) &reply,
2065                         Nfs_timers[Init]);
2066
2067         if (rpc_stat == RPC_SUCCESS) 
2068                 break;
2069         if (rpc_stat != RPC_TIMEDOUT) {
2070                 (void) fprintf(stderr, "lad_remove(%s) RPC call failed : %s\n",
2071                                 name, clnt_sperrno(rpc_stat));
2072         }
2073         if (!LAD_RETRIABLE(rpc_stat)) {
2074                 return(-1);
2075         }
2076         retried++;
2077     }
2078
2079     if (reply.status != NFS3_OK) {
2080         if (reply.status != NFS3ERR_NOENT || !retried) {
2081             (void) fprintf(stderr, "lad_remove(%s) NFS call failed : %s\n",
2082                         name, nfs3_strerror(reply.status));
2083             return(-1);
2084         }
2085     }
2086
2087     file_ptr->state = Nonexistent;
2088
2089     return(0);
2090 }
2091
2092 /*
2093  * Reliably remove a directory in the current directory
2094  */
2095 int
2096 lad_rmdir(sfs_fh_type *file_ptr, char *name)
2097 {
2098     RMDIR3args          args;
2099     RMDIR3res           reply;          /* the reply */
2100     enum clnt_stat      rpc_stat;       /* result from RPC call */
2101     int                 retried = 0;
2102
2103     /*
2104      * This function presumes that the file name does exist and is empty
2105      */
2106     if (file_ptr->attributes3.type != NF3DIR)
2107         return (lad_remove(file_ptr, name));
2108
2109     if (DEBUG_CHILD_RPC) {
2110         (void) fprintf(stderr, "%s:lad_rmdir: %lx[%lx] %s\n", sfs_Myname,
2111                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
2112         (void) fflush(stderr);
2113     }
2114
2115     /* CONSTCOND */
2116     while (1) {
2117         /* set up the arguments */
2118         args.object.name = name;
2119         (void) memmove((char *) &args.object.dir, (char *) &file_ptr->dir->fh3,
2120                 sizeof (nfs_fh3));
2121
2122         /* make the call now */
2123         rpc_stat = clnt_call(NFS_client, NFSPROC3_RMDIR,
2124                         xdr_RMDIR3args, (char *) &args,
2125                         xdr_RMDIR3res, (char *) &reply,
2126                         Nfs_timers[Init]);
2127
2128         if (rpc_stat == RPC_SUCCESS) 
2129                 break;
2130         if (rpc_stat != RPC_TIMEDOUT) {
2131                 (void) fprintf(stderr, "lad_rmdir(%s) RPC call failed : %s\n",
2132                                 name, clnt_sperrno(rpc_stat));
2133         }
2134         if (!LAD_RETRIABLE(rpc_stat)) {
2135                 return(-1);
2136         }
2137         retried++;
2138     }
2139
2140     if (reply.status != NFS3_OK) {
2141         if (reply.status != NFS3ERR_NOENT || !retried) {
2142             (void) fprintf(stderr, "lad_rmdir(%s) NFS call failed : %s\n",
2143                         name, nfs3_strerror(reply.status));
2144             return(-1);
2145         }
2146     }
2147
2148     file_ptr->state = Nonexistent;
2149
2150     return(0);
2151 }
2152
2153 /*
2154  * Reliably create a symlink in the current directory
2155  */
2156 int
2157 lad_symlink(sfs_fh_type *file_ptr, char *target, char *name)
2158 {
2159     SYMLINK3args        args;
2160     SYMLINK3res         reply;                  /* the reply */
2161     char                sym_data[NFS_MAXPATHLEN];       /* symlink data */
2162     enum clnt_stat      rpc_stat;               /* result from RPC call */
2163     int                 retried = 0;
2164
2165     /*
2166      * This function presumes that the file name does not already exist
2167      */
2168     if (DEBUG_CHILD_RPC) {
2169         (void) fprintf(stderr, "%s:lad_symlink: %lx[%lx] %s -> %s\n", sfs_Myname,
2170                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name, target);
2171         (void) fflush(stderr);
2172     }
2173
2174     /* CONSTCOND */
2175     while (1) {
2176         /* set up the arguments */
2177          (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
2178                 sizeof (nfs_fh3));
2179          args.where.name = name;
2180
2181         (void) strcpy(sym_data, "./");
2182         (void) strcat(sym_data, target);
2183         args.symlink.symlink_attributes.size.set_it = TRUE;
2184         args.symlink.symlink_attributes.size.size._p._u = (uint32_t) 0;
2185         args.symlink.symlink_attributes.size.size._p._l = strlen(sym_data);
2186         args.symlink.symlink_data = sym_data;
2187
2188         args.symlink.symlink_attributes.mode.set_it = TRUE;
2189         args.symlink.symlink_attributes.mode.mode = (NFSMODE_LNK | 0777);
2190         args.symlink.symlink_attributes.uid.set_it = TRUE;
2191         args.symlink.symlink_attributes.uid.uid = Cur_uid;
2192         args.symlink.symlink_attributes.gid.set_it = TRUE;
2193         args.symlink.symlink_attributes.gid.gid = Cur_gid;
2194         args.symlink.symlink_attributes.atime.set_it = TRUE;
2195         args.symlink.symlink_attributes.atime.atime.seconds = Cur_time.esec;
2196         args.symlink.symlink_attributes.atime.atime.nseconds =
2197                                                 Cur_time.usec * 1000;
2198         args.symlink.symlink_attributes.mtime.set_it = TRUE;
2199         args.symlink.symlink_attributes.mtime.mtime.seconds = Cur_time.esec;
2200         args.symlink.symlink_attributes.mtime.mtime.nseconds =
2201                                                 Cur_time.usec * 1000;
2202
2203
2204         /* make the call now */
2205         rpc_stat = clnt_call(NFS_client, NFSPROC3_SYMLINK,
2206                         xdr_SYMLINK3args, (char *) &args,
2207                         xdr_SYMLINK3res, (char *) &reply,
2208                         Nfs_timers[Init]);
2209         if (rpc_stat == RPC_SUCCESS) 
2210                 break;
2211         if (rpc_stat != RPC_TIMEDOUT) {
2212                 (void) fprintf(stderr, "lad_symlink(%s) RPC call failed : %s\n",
2213                                 name, clnt_sperrno(rpc_stat));
2214         }
2215         if (!LAD_RETRIABLE(rpc_stat)) {
2216                 return(-1);
2217         }
2218         retried++;
2219     }
2220
2221     if (reply.status != NFS3_OK) {
2222         if (reply.status != NFS3ERR_EXIST || !retried) {
2223             (void) fprintf(stderr, "lad_symlink(%s, %s) NFS call failed : %s\n",
2224                         target, name, nfs3_strerror(reply.status));
2225             return(-1);
2226         }
2227     }
2228
2229     /*
2230      * SYMLINK may not return a fh. If we try to
2231      * access this symlink (eg, remove(), readlink())
2232      * before we do a lookup, we won't have a fh to use.
2233      * So, we do a lookup call here.
2234      * If it fails, we fill in what we can.
2235      */  
2236     return (lad_lookup(file_ptr, name));
2237 }
2238
2239 /*
2240  * Reliably create a directory in the current directory
2241  */
2242 int
2243 lad_mkdir(sfs_fh_type *file_ptr, char *name)
2244 {
2245     MKDIR3args          args;
2246     MKDIR3res           reply;                  /* the reply */
2247     enum clnt_stat      rpc_stat;               /* result from RPC call */
2248     int                 retried = 0;
2249
2250     /*
2251      * This function presumes that the file name does not already exist
2252      */
2253     if (DEBUG_CHILD_RPC) {
2254         (void) fprintf(stderr, "%s:lad_mkdir: %lx[%lx] %s\n", sfs_Myname,
2255                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
2256         (void) fflush(stderr);
2257     }
2258
2259     /* CONSTCOND */
2260     while (1) {
2261         /* set up the arguments */
2262         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
2263                 sizeof (nfs_fh3));
2264         args.where.name = name;
2265         args.attributes.mode.set_it = TRUE;
2266         args.attributes.mode.mode = (NFSMODE_DIR | 0777);
2267         args.attributes.uid.set_it = TRUE;
2268         args.attributes.uid.uid = Cur_uid;
2269         args.attributes.gid.set_it = TRUE;
2270         args.attributes.gid.gid = Cur_gid;
2271         args.attributes.size.set_it = TRUE;
2272         args.attributes.size.size._p._u = 0;
2273         args.attributes.size.size._p._l = 512;
2274         args.attributes.atime.set_it = TRUE;
2275         args.attributes.atime.atime.seconds = Cur_time.esec;
2276         args.attributes.atime.atime.nseconds = Cur_time.usec * 1000;
2277         args.attributes.mtime.set_it = TRUE;
2278         args.attributes.mtime.mtime.seconds = Cur_time.esec;
2279         args.attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
2280
2281         /* make the call now */
2282         rpc_stat = clnt_call(NFS_client, NFSPROC3_MKDIR,
2283                         xdr_MKDIR3args, (char *) &args,
2284                         xdr_MKDIR3res, (char *) &reply,
2285                         Nfs_timers[Init]);
2286
2287         if (rpc_stat == RPC_SUCCESS) 
2288                 break;
2289         if (rpc_stat != RPC_TIMEDOUT) {
2290                 (void) fprintf(stderr, "lad_mkdir(%s) RPC call failed : %s\n",
2291                                 name, clnt_sperrno(rpc_stat));
2292         }
2293         if (!LAD_RETRIABLE(rpc_stat)) {
2294                 return(-1);
2295         }
2296         retried++;
2297     }
2298
2299     if (!retried && reply.status == NFS3ERR_EXIST)
2300         return(1);
2301
2302     if (reply.status != NFS3_OK) {
2303         if (reply.status != NFS3ERR_EXIST || !retried) {
2304             (void) fprintf(stderr, "lad_mkdir(%s) NFS call failed : %s\n",
2305                         name, nfs3_strerror(reply.status));
2306             return(-1);
2307         }
2308         /*
2309          * If the first mkdir suceeded but the reply as dropped and
2310          * was retransmitted, we still need to lookup the attributes
2311          */
2312         if (lad_lookup(file_ptr, name))
2313            return (-1);
2314     } else {
2315         (void) memmove((char *) &file_ptr->fh3,
2316                    (char *) &reply.resok.obj.handle,
2317                    sizeof (nfs_fh3));
2318         (void) strcpy(file_ptr->file_name, name);
2319         (void) memmove((char *) &file_ptr->attributes3,
2320                    (char *) &reply.resok.obj_attributes.attr,
2321                    sizeof(file_ptr->attributes3));
2322         file_ptr->size = fh_size(file_ptr);
2323     }
2324     file_ptr->state = Empty_dir;
2325
2326     return(0);
2327 }
2328
2329 /*
2330  * Reliably commit a file
2331  */
2332 static int
2333 lad_commit(sfs_fh_type *file_ptr)
2334 {
2335     COMMIT3args                 args;
2336     COMMIT3res                  reply;          /* the reply */
2337     enum clnt_stat              rpc_stat;       /* result from RPC call */
2338
2339     if (DEBUG_CHILD_RPC) {
2340         (void) fprintf(stderr, "%s:lad_commit: %lx[%lx]\n",
2341                         sfs_Myname,
2342                         (int32_t) file_ptr, (int32_t) file_ptr->dir);
2343         (void) fflush(stderr);
2344     }
2345
2346     /* set up the arguments */
2347     (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
2348                 sizeof (nfs_fh3));
2349     args.offset._p._u = args.offset._p._l = (uint32_t) 0;
2350     args.count = file_ptr->attributes3.size._p._l;
2351
2352     /* CONSTCOND */
2353     while (1) {
2354         rpc_stat = clnt_call(NFS_client, NFSPROC3_COMMIT,
2355                                 xdr_COMMIT3args, (char *) &args,
2356                                 xdr_COMMIT3res, (char *) &reply,
2357                                 Nfs_timers[Init]);
2358         if (rpc_stat == RPC_SUCCESS) 
2359             break;
2360         if (rpc_stat != RPC_TIMEDOUT) {
2361             (void) fprintf(stderr, "lad_commit() RPC call failed : %s\n",
2362                                 clnt_sperrno(rpc_stat));
2363         }
2364         if (!LAD_RETRIABLE(rpc_stat)) {
2365                 return(-1);
2366         }
2367     }
2368
2369     return(0);
2370 }
2371
2372 /*
2373  * Reliably write a file in the current directory
2374  */
2375 int
2376 lad_write(sfs_fh_type *file_ptr, int32_t offset, int32_t length)
2377 {
2378     static char                 *buf = NULL;    /* the data buffer */
2379     int32_t                     size;           /* size of data write */
2380     int32_t                     cur_cnt;
2381     WRITE3args                  args;
2382     WRITE3res                   reply;          /* the reply */
2383     enum clnt_stat              rpc_stat;       /* result from RPC call */
2384     int                         async = 1;
2385
2386     if (DEBUG_CHILD_RPC) {
2387         (void) fprintf(stderr, "%s:lad_write: %lx[%lx] %ld %ld\n",
2388                         sfs_Myname,
2389                         (int32_t) file_ptr, (int32_t) file_ptr->dir, offset, length);
2390         (void) fflush(stderr);
2391     }
2392
2393     /*
2394      * This function presumes that the file name does exist
2395      * Initialize write buffer to known value
2396      */
2397     if (buf == NULL) {
2398         buf = init_write_buffer();
2399     }
2400
2401     /*
2402      * If a short file write don't bother with the commit, just write sync.
2403      */
2404     if (length <= Bytes_per_block)
2405         async = 0;
2406
2407     /* set up the arguments */
2408     (void) memmove((char *) &args.file, (char *) &file_ptr->fh3,
2409                 sizeof (nfs_fh3));
2410     args.offset._p._u = 0;
2411     args.offset._p._l = offset;
2412     if (async)
2413             args.stable = UNSTABLE;
2414     else
2415             args.stable = FILE_SYNC;
2416
2417     size = Bytes_per_block;
2418     for (cur_cnt = 0; cur_cnt < length; cur_cnt += size) {
2419         if ((cur_cnt + size) > length)
2420                 size = length - cur_cnt;
2421
2422         if (size == 0)
2423             break;
2424
2425         args.count = size;
2426         args.data.data_len = size;
2427         args.data.data_val = buf;
2428
2429         /* make the call now */
2430         /* CONSTCOND */
2431         while (1) {
2432             rpc_stat = clnt_call(NFS_client, NFSPROC3_WRITE,
2433                                 xdr_WRITE3args, (char *) &args,
2434                                 xdr_WRITE3res, (char *) &reply,
2435                                 Nfs_timers[Init]);
2436
2437             if (rpc_stat == RPC_SUCCESS) 
2438                 break;
2439             if (rpc_stat != RPC_TIMEDOUT) {
2440                 (void) fprintf(stderr, "lad_write() RPC call failed : %s\n",
2441                                 clnt_sperrno(rpc_stat));
2442             }
2443             if (!LAD_RETRIABLE(rpc_stat)) {
2444                 return(-1);
2445             }
2446         }
2447         if (reply.status != NFS3_OK) {
2448             (void) fprintf(stderr, "lad_write() NFS call failed : %s\n",
2449                         nfs3_strerror(reply.status));
2450             return(-1);
2451         }
2452         file_ptr->state = Exists;
2453         (void) memmove((char *) &file_ptr->attributes3,
2454                                 (char *) &reply.resok.file_wcc.after.attr,
2455                                 sizeof (file_ptr->attributes3));
2456         file_ptr->size = fh_size(file_ptr);
2457
2458         args.offset._p._l += size;
2459     }
2460
2461     if (async)
2462         (void) lad_commit(file_ptr);
2463     return(0);
2464 }
2465
2466 /*
2467  * Reliably create a file in the current directory
2468  */
2469 int
2470 lad_create(sfs_fh_type *file_ptr, char *name)
2471 {
2472     CREATE3args         args;
2473     CREATE3res          reply;                  /* the reply */
2474     enum clnt_stat      rpc_stat;               /* result from RPC call */
2475     int                 retried = 0;
2476
2477     /*
2478      * This function presumes that the file name does not already exist
2479      */
2480     if (DEBUG_CHILD_RPC) {
2481         (void) fprintf(stderr, "%s:lad_create: %lx[%lx] %s\n", sfs_Myname,
2482                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
2483         (void) fflush(stderr);
2484     }
2485
2486     /* CONSTCOND */
2487     while (1) {
2488         /* set up the arguments */
2489         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh3,
2490                 sizeof (nfs_fh3));
2491         args.where.name = name;
2492         args.how.mode = UNCHECKED;
2493         args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
2494         args.how.createhow3_u.obj_attributes.mode.mode = (NFSMODE_REG | 0666);
2495         args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
2496         args.how.createhow3_u.obj_attributes.uid.uid = Cur_uid;
2497         args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
2498         args.how.createhow3_u.obj_attributes.gid.gid = Cur_gid;
2499         args.how.createhow3_u.obj_attributes.atime.set_it = TRUE;
2500         args.how.createhow3_u.obj_attributes.atime.atime.seconds =
2501                                                 Cur_time.esec;
2502         args.how.createhow3_u.obj_attributes.atime.atime.nseconds =
2503                                                 Cur_time.usec * 1000;
2504         args.how.createhow3_u.obj_attributes.mtime.set_it = TRUE;
2505         args.how.createhow3_u.obj_attributes.mtime.mtime.seconds =
2506                                                 Cur_time.esec;
2507         args.how.createhow3_u.obj_attributes.mtime.mtime.nseconds =
2508                                                 Cur_time.usec * 1000;
2509         args.how.createhow3_u.obj_attributes.size.set_it = TRUE;
2510         args.how.createhow3_u.obj_attributes.size.size._p._u =
2511                                                 (uint32_t) 0;
2512         args.how.createhow3_u.obj_attributes.size.size._p._l =
2513                                                 (uint32_t) 0;
2514
2515         /* make the call now */
2516         rpc_stat = clnt_call(NFS_client, NFSPROC3_CREATE,
2517                         xdr_CREATE3args, (char *) &args,
2518                         xdr_CREATE3res, (char *) &reply,
2519                         Nfs_timers[Init]);
2520
2521         if (rpc_stat == RPC_SUCCESS) 
2522                 break;
2523         if (rpc_stat != RPC_TIMEDOUT) {
2524                 (void) fprintf(stderr, "lad_create(%s) RPC call failed : %s\n",
2525                                 name, clnt_sperrno(rpc_stat));
2526         }
2527         if (!LAD_RETRIABLE(rpc_stat)) {
2528                 return(-1);
2529         }
2530         retried++;
2531     }
2532
2533     if (!retried && reply.status == NFS3ERR_EXIST) {
2534         return(1);
2535     }
2536
2537     if (reply.status != NFS3_OK) {
2538         if (reply.status != NFS3ERR_EXIST || !retried) {
2539             (void) fprintf(stderr, "lad_create(%s) NFS call failed : %s\n",
2540                         name, nfs3_strerror(reply.status));
2541             return(-1);
2542         }
2543         /*
2544          * If the first create suceeded but the reply as dropped and
2545          * was retransmitted, we still need to lookup the attributes
2546          */
2547         if (lad_lookup(file_ptr, name))
2548            return (-1);
2549     } else {
2550         (void) memmove((char *) &file_ptr->fh3,
2551                    (char *) &reply.resok.obj.handle,
2552                    sizeof (nfs_fh3));
2553         (void) strcpy(file_ptr->file_name, name);
2554         (void) memmove((char *) &file_ptr->attributes3,
2555                    (char *) &reply.resok.obj_attributes.attr,
2556                    sizeof(file_ptr->attributes3));
2557         file_ptr->size = fh_size(file_ptr);
2558     }
2559
2560     file_ptr->state = Exists;
2561     /*
2562      * Directories are created as Empty_dir, when a file is created it
2563      * becomes an Exists.
2564      */
2565     file_ptr->dir->state = Exists;
2566
2567     return(0);
2568 }
2569
2570 /*
2571  * Reliably set the size of a file in the current directory
2572  */
2573 int
2574 lad_truncate(sfs_fh_type *file_ptr, int32_t size)
2575 {
2576     SETATTR3args        args;
2577     SETATTR3res         reply;          /* the reply */
2578     enum clnt_stat      rpc_stat;       /* result from RPC call */
2579
2580     /*
2581      * This function presumes that the file name already exists
2582      */
2583     if (DEBUG_CHILD_RPC) {
2584         (void) fprintf(stderr, "%s:lad_truncate: %lx[%lx] %ld\n", sfs_Myname,
2585                         (int32_t) file_ptr, (int32_t) file_ptr->dir, size);
2586         (void) fflush(stderr);
2587     }
2588
2589     /* CONSTCOND */
2590     while (1) {
2591         /*
2592          * set up the arguments
2593          * Set the mode and times as well
2594          */
2595         (void) memmove((char *) &args.object, (char *) &file_ptr->fh3,
2596                                                         sizeof (nfs_fh3));
2597         args.new_attributes.mode.set_it = TRUE;
2598         args.new_attributes.mode.mode = (uint32_t) 0666;
2599         args.new_attributes.uid.set_it = FALSE;
2600         args.new_attributes.uid.uid = (uint32_t) -1;
2601         args.new_attributes.gid.set_it = FALSE;
2602         args.new_attributes.gid.gid = (uint32_t) -1;
2603         args.new_attributes.size.set_it = TRUE;
2604         args.new_attributes.size.size._p._u = 0;
2605         args.new_attributes.size.size._p._l = size;
2606         args.new_attributes.atime.set_it = TRUE;
2607         args.new_attributes.atime.atime.seconds = Cur_time.esec;
2608         args.new_attributes.atime.atime.nseconds = Cur_time.usec * 1000;
2609         args.new_attributes.mtime.set_it = TRUE;
2610         args.new_attributes.mtime.mtime.seconds = Cur_time.esec;
2611         args.new_attributes.mtime.mtime.nseconds = Cur_time.usec * 1000;
2612         args.guard.check = FALSE;
2613
2614         /* make the call */
2615         rpc_stat = clnt_call(NFS_client, NFSPROC3_SETATTR,
2616                         xdr_SETATTR3args, (char *) &args,
2617                         xdr_SETATTR3res, (char *) &reply,
2618                         Nfs_timers[Init]);
2619
2620         if (rpc_stat == RPC_SUCCESS) 
2621                 break;
2622         if (rpc_stat != RPC_TIMEDOUT) {
2623                 (void)fprintf(stderr,
2624                                 "lad_truncate(%ld) RPC call failed : %s\n",
2625                                 size, clnt_sperrno(rpc_stat));
2626         }
2627         if (!LAD_RETRIABLE(rpc_stat)) {
2628                 return(-1);
2629         }
2630     }
2631
2632     if (reply.status != NFS3_OK) {
2633         (void) fprintf(stderr, "lad_truncate(%ld) NFS call failed : %s\n",
2634                         size, nfs3_strerror(reply.status));
2635         return(-1);
2636     }
2637     (void) memmove(&file_ptr->attributes3,
2638                    &reply.resok.obj_wcc.after.attr,
2639                    sizeof (file_ptr->attributes3));
2640     file_ptr->size = fh_size(file_ptr);
2641
2642     return(0);
2643 }
2644
2645 static char *
2646 nfs3_strerror(int status)
2647 {
2648     static char str[40];
2649     switch (status) {
2650         case NFS3_OK:
2651             (void) strcpy(str, "no error");
2652             break;
2653         case NFS3ERR_PERM:
2654             (void) strcpy(str, "Not owner");
2655             break;
2656         case NFS3ERR_NOENT:
2657             (void) strcpy(str, "No such file or directory");
2658             break;
2659         case NFS3ERR_IO:
2660             (void) strcpy(str, "I/O error");
2661             break;
2662         case NFS3ERR_NXIO:
2663             (void) strcpy(str, "No such device or address");
2664             break;
2665         case NFS3ERR_ACCES:
2666             (void) strcpy(str, "Permission denied");
2667             break;
2668         case NFS3ERR_EXIST:
2669             (void) strcpy(str, "File exists");
2670             break;
2671         case NFS3ERR_XDEV:
2672             (void) strcpy(str, "Cross-device link");
2673             break;
2674         case NFS3ERR_NODEV:
2675             (void) strcpy(str, "No such device");
2676             break;
2677         case NFS3ERR_NOTDIR:
2678             (void) strcpy(str, "Not a directory");
2679             break;
2680         case NFS3ERR_ISDIR:
2681             (void) strcpy(str, "Is a directory");
2682             break;
2683         case NFS3ERR_INVAL:
2684             (void) strcpy(str, "Invalid argument");
2685             break;
2686         case NFS3ERR_FBIG:
2687             (void) strcpy(str, "File too large");
2688             break;
2689         case NFS3ERR_NOSPC:
2690             (void) strcpy(str, "No space left on device");
2691             break;
2692         case NFS3ERR_ROFS:
2693             (void) strcpy(str, "Read-only file system");
2694             break;
2695         case NFS3ERR_MLINK:
2696             (void) strcpy(str, "Too many links");
2697             break;
2698         case NFS3ERR_NAMETOOLONG:
2699             (void) strcpy(str, "File name too long");
2700             break;
2701         case NFS3ERR_NOTEMPTY:
2702             (void) strcpy(str, "Directory not empty");
2703             break;
2704         case NFS3ERR_DQUOT:
2705             (void) strcpy(str, "Disc quota exceeded");
2706             break;
2707         case NFS3ERR_STALE:
2708             (void) strcpy(str, "Stale NFS file handle");
2709             break;
2710         case NFS3ERR_REMOTE:
2711             (void) strcpy(str, "Object is remote");
2712             break;
2713         case NFS3ERR_BADHANDLE:
2714             (void) strcpy(str, "Bad file handle");
2715             break;
2716         case NFS3ERR_NOT_SYNC:
2717             (void) strcpy(str, "Not sync write");
2718             break;
2719         case NFS3ERR_BAD_COOKIE:
2720             (void) strcpy(str, "Bad cookie");
2721             break;
2722         case NFS3ERR_NOTSUPP:
2723             (void) strcpy(str, "Operation not supported");
2724             break;
2725         case NFS3ERR_TOOSMALL:
2726             (void) strcpy(str, "Value too small");
2727             break;
2728         case NFS3ERR_SERVERFAULT:
2729             (void) strcpy(str, "Server fault");
2730             break;
2731         case NFS3ERR_BADTYPE:
2732             (void) strcpy(str, "Bad type");
2733             break;
2734         case NFS3ERR_JUKEBOX:
2735             (void) strcpy(str, "Jukebox");
2736             break;
2737         case NFS3ERR_RFS_TIMEOUT:
2738                 (void) strcpy(str, "RFS timeout");
2739         default:
2740             (void) sprintf(str, "Unknown status %d", status);
2741             break;
2742     }
2743     return (str);
2744 }
2745
2746 /* sfs_3_ops.c */