Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / sfs_2_ops.c
1 #ifndef lint
2 static char sfs_c_opsSid[] = "@(#)sfs_2_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_c_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_nosys(void)
45  *      int op_lookup(void)
46  *      int op_readlink(void)
47  *      int op_read(int)
48  *      int op_write(int, int, int)
49  *      int op_create(void)
50  *      int op_remove(void)
51  *      int op_rename(void)
52  *      int op_link(void)
53  *      int op_symlink(void)
54  *      int op_mkdir(void)
55  *      int op_rmdir(void)
56  *      int op_readdir(void)
57  *      int op_fsstat(void)
58  *
59  *.Revision_History
60  *      20-Apr-92       Wittle          Fix i/o offsets randomization.
61  *      05-Jan-92       Pawlowski       Added hooks in for raw data dump.
62  *      04-Dec-91       Keith           Define string.h for SYSV/SVR4.
63  *      28-Nov-91       Teelucksingh    ANSI C
64  *      01-Aug-91       Santa Wiryaman  fix declaration of sfs_srandom()
65  *                                      and sfs_random()
66  *      25-Jun-91       Santa Wiryaman  op_rmdir bug fix: when reply==NFS_OK
67  *                                      Cur_file_ptr->state = Nonexistent
68  *      17-May-90       Richard Bean    Created.
69  */
70
71
72 /*
73  * -------------------------  Include Files  -------------------------
74  */
75
76 /*
77  * ANSI C headers
78  */
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <errno.h>
83  
84 #include <sys/types.h>
85 #include <sys/stat.h> 
86
87 #include <unistd.h>
88
89 #include "sfs_c_def.h"
90
91 /*
92  * --------------------  Local NFS ops function --------------------
93  */
94 static int op_null(void);
95 static int op_getattr(void);
96 static int op_setattr(int);
97 static int op_lookup(void);
98 static int op_readlink(void);
99 static int op_read(int);
100 static int op_write(int, int, int);
101 static int op_create(void);
102 static int op_remove(void);
103 static int op_rename(void);
104 static int op_link(void);
105 static int op_symlink(void);
106 static int op_mkdir(void);
107 static int op_rmdir(void);
108 static int op_readdir(void);
109 static int op_fsstat(void);
110 static int op_nosys(void);
111 static char *nfs2_strerror(int);
112
113 /*
114  * --------------------  NFS ops vector --------------------
115  */
116 /*
117  * per operation information
118  */
119 static sfs_op_type nfsv2_Ops[] = {
120
121 /* name      mix   function        op    call  no  req  req  req  results */
122 /*           pcnt                 class  targ call pcnt cnt  targ         */
123
124  { "null",        0, op_null,      Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
125  { "getattr",    26, op_getattr,   Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
126  { "setattr",     1, op_setattr,   Write,   0,  0,  0.0,  0,   0,  { 0, }},
127  { "root",        0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
128  { "lookup",     36, op_lookup,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
129  { "readlink",    7, op_readlink,  Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
130  { "read",       14, op_read,      Read,    0,  0,  0.0,  0,   0,  { 0, }},
131  { "wrcache",     0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
132  { "write",       7, op_write,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
133  { "create",      1, op_create,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
134  { "remove",      1, op_remove,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
135  { "rename",      0, op_rename,    Write,   0,  0,  0.0,  0,   0,  { 0, }},
136  { "link",        0, op_link,      Write,   0,  0,  0.0,  0,   0,  { 0, }},
137  { "symlink",     0, op_symlink,   Write,   0,  0,  0.0,  0,   0,  { 0, }},
138  { "mkdir",       0, op_mkdir,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
139  { "rmdir",       0, op_rmdir,     Write,   0,  0,  0.0,  0,   0,  { 0, }},
140  { "readdir",     6, op_readdir,   Read,    0,  0,  0.0,  0,   0,  { 0, }},
141  { "fsstat",      1, op_fsstat,    Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
142  { "access",      0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
143  { "commit",      0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
144  { "fsinfo",      0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
145  { "mknod",       0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
146  { "pathconf",    0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
147  { "readdirplus", 0, op_nosys,     Lookup,  0,  0,  0.0,  0,   0,  { 0, }},
148  { "TOTAL",     100, 0,            Lookup,  0,  0,  0.0,  0,   0,  { 0, }}
149 };
150
151 sfs_op_type *Ops;
152
153 /*
154  * --------------------  RPC routines for NFS protocol --------------------
155  */
156
157 void
158 init_ops(void)
159
160     Ops = nfsv2_Ops;
161     nfs_version = NFS_VERSION;
162
163
164 /*
165  * The routines below attempt to do over-the-wire operations.
166  * Each op tries to cause one or more of a particular
167  * NFS operation to go over the wire.  OPs return the success
168  * of their NFS call(s).  Each OP records how many calls it
169  * actually made in global data.
170  *
171  * An array of file information is kept for files existing in
172  * the test directory.  File handles, attributes, names, etc
173  * are stored in this array.
174  *
175  */
176
177 static int
178 op_nosys(void)
179 {
180     /*
181      * This is a generic catcher for operations that either don't
182      * exist or were never implemented.  We will be
183      * kind and simply mark it as a bad call.
184      */
185     Ops[TOTAL].results.bad_calls++;
186     return(0);
187
188 } /* op_nosys */
189
190
191 static int
192 op_null(void)
193 {
194     sfs_op_type         *op_ptr;        /* per operation info */
195     enum clnt_stat      rpc_stat;       /* result from RPC call */
196     struct ladtime      start;
197     struct ladtime      stop;
198     int                 ret;            /* ret val == call success */
199
200     op_ptr = &Ops[NULLCALL];
201     ret = 0;
202
203     /* make the call */
204     sfs_gettime(&start);
205     rpc_stat = clnt_call(NFS_client, NFSPROC_NULL,
206                         xdr_void, (char *)0,
207                         xdr_void, (char *)0,
208                         (Current_test_phase < Warmup_phase)
209                                  ? Nfs_timers[Init]
210                                  : Nfs_timers[op_ptr->call_class]);
211     sfs_gettime(&stop);
212     Cur_time = stop;
213
214     if (rpc_stat == RPC_SUCCESS) {
215         sfs_elapsedtime(op_ptr, &start, &stop);
216         op_ptr->results.good_calls++;
217         Ops[TOTAL].results.good_calls++;
218         ret++;
219     } else {
220         if (DEBUG_CHILD_ERROR) {
221              (void) fprintf(stderr,
222                     "%s: null_op call RPC error %d on file %d\n",
223                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
224         }
225         op_ptr->results.bad_calls++;
226         Ops[TOTAL].results.bad_calls++;
227     }
228     return(ret);
229
230 } /* op_null */
231
232
233 static int
234 op_getattr(void)
235 {
236     sfs_op_type         *op_ptr;        /* per operation info */
237     fhandle_t           fh;             /* fh to do op on */
238     attrstat            reply;          /* the reply */
239     enum clnt_stat      rpc_stat;       /* result from RPC call */
240     struct ladtime      start;
241     struct ladtime      stop;
242     int                 ret;            /* ret val == call success */
243
244     op_ptr = &Ops[GETATTR];
245     ret = 0;
246
247     /* set up the arguments */
248     (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
249                         NFS_FHSIZE);
250
251     /* make the call */
252     sfs_gettime(&start);
253     rpc_stat = clnt_call(NFS_client, NFSPROC_GETATTR,
254                         xdr_getattr, (char *) &fh,
255                         xdr_getattr, (char *) &reply,
256                         (Current_test_phase < Warmup_phase)
257                                  ? Nfs_timers[Init]
258                                  : Nfs_timers[op_ptr->call_class]);
259     sfs_gettime(&stop);
260     Cur_time = stop;
261
262     if (rpc_stat == RPC_SUCCESS) {
263         if (reply.status == NFS_OK) {
264             Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
265             Cur_file_ptr->size = fh_size(Cur_file_ptr);
266         } else {
267             if (DEBUG_CHILD_ERROR) {
268                  (void) fprintf(stderr,
269                         "%s: getattr call NFS error %s on file %d\n",
270                         sfs_Myname, nfs2_strerror(reply.status),
271                         Cur_file_ptr->unique_num);
272             }
273         }
274         sfs_elapsedtime(op_ptr, &start, &stop);
275         op_ptr->results.good_calls++;
276         Ops[TOTAL].results.good_calls++;
277         ret++;
278     } else {
279         if (DEBUG_CHILD_ERROR) {
280              (void) fprintf(stderr,
281                     "%s: getattr call RPC error %d on file %d\n",
282                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
283         }
284         op_ptr->results.bad_calls++;
285         Ops[TOTAL].results.bad_calls++;
286     }
287     return(ret);
288
289 } /* op_getattr */
290
291
292 /*
293  * perform an RPC setattr operation.  If 'truncate_size' is non-negative,
294  * truncate the file to that size.
295  */
296 static int
297 op_setattr(
298     int         truncate_size)
299 {
300     sfs_op_type         *op_ptr;        /* per operation info */
301     sattrargs           args;
302     attrstat            reply;          /* the reply */
303     enum clnt_stat      rpc_stat;       /* result from RPC call */
304     struct ladtime      start;
305     struct ladtime      stop;
306     int                 ret;            /* ret val == call success */
307
308     op_ptr = &Ops[SETATTR];
309     ret = 0;
310
311     /* set up the arguments */
312     args.attributes.mode = 0666;
313     args.attributes.uid = (unsigned int) -1;
314     args.attributes.gid = (unsigned int) -1;
315     args.attributes.size = (unsigned int) -1;
316     args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
317     args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
318     args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
319     args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
320     (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
321                         NFS_FHSIZE);
322
323     /* handle file truncations */
324     if (truncate_size >= 0) {
325         if (truncate_size > Cur_file_ptr->attributes2.size)
326             args.attributes.size = (unsigned int) 0;
327         else
328             args.attributes.size = (unsigned int) Cur_file_ptr->attributes2.size
329                                    - truncate_size;
330     }
331
332     /* make the call */
333     sfs_gettime(&start);
334     rpc_stat = clnt_call(NFS_client, NFSPROC_SETATTR,
335                         xdr_setattr, (char *) &args,
336                         xdr_setattr, (char *) &reply,
337                         (Current_test_phase < Warmup_phase)
338                                  ? Nfs_timers[Init]
339                                  : Nfs_timers[op_ptr->call_class]);
340
341     sfs_gettime(&stop);
342     Cur_time = stop;
343
344     if (rpc_stat == RPC_SUCCESS) {
345         if (reply.status == NFS_OK) {
346             Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
347             Cur_file_ptr->size = fh_size(Cur_file_ptr);
348         } else {
349             if (DEBUG_CHILD_ERROR) {
350                  (void) fprintf(stderr,
351                         "%s: setattr call NFS error %s on file %d\n",
352                         sfs_Myname, nfs2_strerror(reply.status),
353                         Cur_file_ptr->unique_num);
354             }
355         }
356         sfs_elapsedtime(op_ptr, &start, &stop);
357         op_ptr->results.good_calls++;
358         Ops[TOTAL].results.good_calls++;
359         ret++;
360     } else {
361         if (DEBUG_CHILD_ERROR) {
362              (void) fprintf(stderr,
363                     "%s: setattr call RPC error %d on file %d\n",
364                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
365         }
366         op_ptr->results.bad_calls++;
367         Ops[TOTAL].results.bad_calls++;
368     }
369     return(ret);
370
371 } /* op_setattr */
372
373
374 static int
375 op_lookup(void)
376 {
377     sfs_op_type         *op_ptr;        /* per operation info */
378     diropargs           args;
379     diropres            reply;          /* the reply */
380     enum clnt_stat      rpc_stat;       /* result from RPC call */
381     struct ladtime      start;
382     struct ladtime      stop;
383     int                 ret;            /* ret val == call success */
384
385     op_ptr = &Ops[LOOKUP];
386     ret = 0;
387
388     /* set up the arguments */
389     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
390                         NFS_FHSIZE);
391     args.name = Cur_filename;
392
393     /* make the call */
394     sfs_gettime(&start);
395     rpc_stat = clnt_call(NFS_client, NFSPROC_LOOKUP,
396                         xdr_lookup, (char *) &args,
397                         xdr_lookup, (char *) &reply,
398                         (Current_test_phase < Warmup_phase)
399                                  ? Nfs_timers[Init]
400                                  : Nfs_timers[op_ptr->call_class]);
401     sfs_gettime(&stop);
402     Cur_time = stop;
403
404     if (rpc_stat == RPC_SUCCESS) {
405         if (reply.status == NFS_OK) {
406             Cur_file_ptr->state = Exists;
407             (void) memmove((char *) &Cur_file_ptr->fh2,
408                         (char *) &reply.diropres_u.diropres.file,
409                         NFS_FHSIZE);
410             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
411             Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
412             Cur_file_ptr->size = fh_size(Cur_file_ptr);
413         } else {
414             /* We do lookup Nonexistent and this is not an error */
415             if (reply.status != NFSERR_NOENT ||
416                         Cur_file_ptr->state != Nonexistent) {
417                 if (DEBUG_CHILD_ERROR) {
418                      (void) fprintf(stderr,
419                         "%s: lookup call NFS error %s on file %d\n",
420                         sfs_Myname, nfs2_strerror(reply.status),
421                         Cur_file_ptr->unique_num);
422                 }
423             }
424
425         }
426         sfs_elapsedtime(op_ptr, &start, &stop);
427         op_ptr->results.good_calls++;
428         Ops[TOTAL].results.good_calls++;
429         ret++;
430     } else {
431         if (DEBUG_CHILD_ERROR) {
432              (void) fprintf(stderr, "%s: lookup call RPC error %d on file %d\n",
433                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
434         }
435         op_ptr->results.bad_calls++;
436         Ops[TOTAL].results.bad_calls++;
437     }
438     return(ret);
439
440 } /* op_lookup */
441
442
443 static int
444 op_readlink(void)
445 {
446     sfs_op_type         *op_ptr;                /* per operation info */
447     fhandle_t           fh;                     /* fh to do op on */
448     readlinkres         reply;                  /* the reply */
449     char                sym_data[NFS_MAXPATHLEN];
450     int                 len;                    /* length of symlink data */
451     enum clnt_stat      rpc_stat;               /* result from RPC call */
452     struct ladtime      start;
453     struct ladtime      stop;
454     int                 ret;                    /* ret val == call success */
455
456     op_ptr = &Ops[READLINK];
457     ret = 0;
458
459     /* set up the arguments */
460     /*
461      * Note: this fh may be bogus because SYMLINK does
462      * not return a fh ... only a status.  So unless we have
463      * done a LOOKUP on this guy, the fh will probably be bad.
464      * If it is bad it shows up as a symlink error in the results.
465      */
466     (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
467                         NFS_FHSIZE);
468
469     /* Have lower layers fill in the data directly. */
470     reply.readlinkres_u.data = sym_data;
471     len = 0;
472
473     /* make the call now */
474     sfs_gettime(&start);
475     rpc_stat = clnt_call(NFS_client, NFSPROC_READLINK,
476                         xdr_readlink, (char *) &fh,
477                         xdr_readlink, (char *) &reply,
478                         (Current_test_phase < Warmup_phase)
479                                  ? Nfs_timers[Init]
480                                  : Nfs_timers[op_ptr->call_class]);
481     sfs_gettime(&stop);
482     Cur_time = stop;
483
484     if (rpc_stat == RPC_SUCCESS) {
485         if (reply.status == NFS_OK) {
486             if (DEBUG_CHILD_RPC) {
487                 len = reply.readlinkres_u.len;
488                 sym_data[len] = '\0';
489                 (void) fprintf(stderr, "%s: READLINK on %s returned %s\n",
490                                     sfs_Myname, Cur_filename, sym_data);
491                 (void) fflush(stderr);
492             }
493         } else {
494             if (DEBUG_CHILD_ERROR) {
495                  (void) fprintf(stderr,
496                         "%s: readlink call NFS error %s on file %d\n",
497                         sfs_Myname, nfs2_strerror(reply.status),
498                         Cur_file_ptr->unique_num);
499             }
500         }
501         sfs_elapsedtime(op_ptr, &start, &stop);
502         op_ptr->results.good_calls++;
503         Ops[TOTAL].results.good_calls++;
504         ret++;
505     } else {
506         if (DEBUG_CHILD_ERROR) {
507              (void) fprintf(stderr,
508                     "%s: readlink call RPC error %d on file %d\n",
509                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
510         }
511         op_ptr->results.bad_calls++;
512         Ops[TOTAL].results.bad_calls++;
513     }
514     return(ret);
515
516 } /* op_readlink */
517
518
519 /*
520  * perform an RPC read operation of length 'xfer_size'
521  */
522 static int
523 op_read(
524     int                         xfer_size)
525 {
526     sfs_op_type                 *op_ptr;        /* per operation info */
527     int                         cur_cnt;
528     int                         max_cnt;        /* packet ctrs */
529     char                        buf[DEFAULT_MAX_BUFSIZE];/* data buffer */
530     readargs                    args;
531     readres                     reply;          /* the reply */
532     enum clnt_stat              rpc_stat;       /* result from RPC call */
533     struct ladtime              start;
534     struct ladtime              stop;
535     int                         size;
536     int                         j;
537     int                         ret;            /* ret val == call success */
538
539     op_ptr = &Ops[READ];
540     ret = 0;
541
542     /* set up the arguments */
543     (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
544                         NFS_FHSIZE);
545
546     /*
547      * Don't allow a read of less than one block size
548      */
549     if (xfer_size < Bytes_per_block)
550         xfer_size = Bytes_per_block;
551
552     /*
553      * randomly choose an offset that is a multiple of the block size
554      * and constrained by making the transfer fit within the file
555      */
556     if (Cur_file_ptr->attributes2.size > xfer_size) {
557         args.offset = Bytes_per_block * (sfs_random() %
558                         (((Cur_file_ptr->attributes2.size - xfer_size)
559                         / Bytes_per_block) + 1));
560     } else
561         args.offset = 0;
562
563     /* first read the whole buffers, then the fragment */
564     for (j = 0; j < 2; j++) {
565
566         if (j == 0) {
567             size = Bytes_per_block;
568             max_cnt = xfer_size / Bytes_per_block;
569         } else {
570             /* 1KB - (Kb_per_block -1) KB fragment */
571             size = xfer_size % Bytes_per_block;
572             max_cnt = 1;
573         }
574         if (size == 0)
575             continue;
576
577         /* check our stats to see if this would overflow */
578         if (!Timed_run) {
579             if (op_ptr->target_calls > 0) {
580                 if ((op_ptr->results.good_calls + max_cnt)
581                      > op_ptr->target_calls) {
582                     max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
583                 }
584             }
585         }
586
587         args.count = size;
588         args.totalcount = size;         /* unused */
589
590         /* Have lower layers fill in the data directly.  */
591         reply.readres_u.reply.data.data_val = buf;
592
593         if (DEBUG_CHILD_RPC) {
594             (void) fprintf(stderr, "read: %d buffers\n", max_cnt);
595             (void) fflush(stderr);
596         }
597
598         /* make the call(s) now */
599         for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
600
601             /* capture length for possible dump */
602             Dump_length = fh_size(Cur_file_ptr);
603
604             sfs_gettime(&start);
605             rpc_stat = clnt_call(NFS_client, NFSPROC_READ,
606                                 xdr_read, (char *) &args,
607                                 xdr_read, (char *) &reply,
608                                 (Current_test_phase < Warmup_phase)
609                                      ? Nfs_timers[Init]
610                                      : Nfs_timers[op_ptr->call_class]);
611             sfs_gettime(&stop);
612             Cur_time = stop;
613
614             /* capture count and offset for possible dump */
615             Dump_count = (rpc_stat == RPC_SUCCESS && reply.status == NFS_OK)
616                             ? reply.readres_u.reply.data.data_len : 0;
617             Dump_offset = args.offset;
618
619             if (rpc_stat == RPC_SUCCESS) {
620                 if (reply.status == NFS_OK) {
621                     Cur_file_ptr->state = Exists;
622                     Cur_file_ptr->attributes2 =
623                                         reply.readres_u.reply.attributes;
624                     Cur_file_ptr->size = fh_size(Cur_file_ptr);
625                     size = reply.readres_u.reply.data.data_len;
626
627                     if (DEBUG_CHILD_RPC) {
628                         (void) fprintf(stderr, "%s: READ %s %d bytes\n",
629                                            sfs_Myname, Cur_filename, size);
630                         (void) fflush(stderr);
631                     }
632                     args.offset += size;
633                 } else {
634                     if (DEBUG_CHILD_ERROR) {
635                          (void) fprintf(stderr,
636                                 "%s: read call NFS error %s on file %d\n",
637                                 sfs_Myname, nfs2_strerror(reply.status),
638                                 Cur_file_ptr->unique_num);
639                     }
640                 }
641                 sfs_elapsedtime(op_ptr, &start, &stop);
642                 op_ptr->results.good_calls++;
643                 Ops[TOTAL].results.good_calls++;
644                 ret++;
645             } else {
646                 if (DEBUG_CHILD_ERROR) {
647                      (void) fprintf(stderr,
648                             "%s: read call RPC error %d on file %d\n",
649                             sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
650                 }
651                 op_ptr->results.bad_calls++;
652                 Ops[TOTAL].results.bad_calls++;
653             }
654         } /* for reading max_cnt packets */
655     } /* for buffers and fragments */
656     return(ret);
657
658 } /* op_read */
659
660
661 char *
662 init_write_buffer(
663     void)
664 {
665     uint32_t *bp;
666     static uint32_t write_buf[DEFAULT_MAX_BUFSIZE / sizeof(uint32_t)];
667     uint32_t *be  = write_buf + (sizeof(write_buf) /
668                                                 sizeof(uint32_t));
669
670     if (write_buf[0] != (uint32_t)0xdeadbeef) {
671         for (bp = write_buf; bp < be; bp++)
672             *bp = (uint32_t)0xdeadbeef;
673     }
674     return (char *)write_buf;
675 }
676
677 /*
678  * Perform and RPC write operation of length 'xfer_size'.  If 'append_flag'
679  * is true, then write the data to the end of the file.
680  */
681 /* ARGSUSED2 */
682 static int
683 op_write(
684     int                 xfer_size,
685     int                 append_flag,
686     int                 stable)
687 {
688     sfs_op_type                 *op_ptr;        /* per operation info */
689     static char                 *buf = NULL;    /* the data buffer */
690     int                         size;           /* size of data write */
691     int                         cur_cnt;        /* controls # NFS calls */
692     int                         max_cnt;
693     writeargs                   args;
694     attrstat                    reply;          /* the reply */
695     enum clnt_stat              rpc_stat;       /* result from RPC call */
696     struct ladtime              start;
697     struct ladtime              stop;
698     int                         j;
699     int                         ret;            /* ret val == call success */
700
701     /*
702      * Initialize write buffer to known value
703      */
704     if (buf == NULL) {
705         buf = init_write_buffer();
706     }
707     op_ptr = &Ops[WRITE];
708     ret = 0;
709
710     /* set up the arguments */
711     (void) memmove((char *) &args.file, (char *) &Cur_file_ptr->fh2,
712                         NFS_FHSIZE);
713     args.beginoffset = 0;       /* unused */
714
715     if (append_flag == 1) {
716         args.offset = Cur_file_ptr->attributes2.size;
717     } else {
718         /*
719          * randomly choose an offset that is a multiple of the block size
720          * and constrained by making the transfer fit within the file
721          */
722         if (Cur_file_ptr->attributes2.size > xfer_size) {
723             args.offset = Bytes_per_block * (sfs_random() %
724                             (((Cur_file_ptr->attributes2.size - xfer_size)
725                             / Bytes_per_block) + 1));
726         } else
727             args.offset = 0;
728     }
729
730     /* first write the whole buffers, then the fragment */
731     for (j = 0; j < 2; j++) {
732
733         if (j == 0) {
734             size = Bytes_per_block;
735             max_cnt = xfer_size / Bytes_per_block;
736         } else {
737             /* 1KB - (Kb_per_block - 1) KB fragment */
738             size = xfer_size % Bytes_per_block;
739             max_cnt = 1;
740         }
741         if (size == 0)
742             continue;
743
744         args.totalcount = size; /* unused */
745         args.data.data_len = size;
746         args.data.data_val = buf;
747
748         /* check our stats to see if this would overflow */
749         if (!Timed_run) {
750             if (op_ptr->target_calls > 0) {
751                 if ((op_ptr->results.good_calls + max_cnt)
752                      > op_ptr->target_calls) {
753                     max_cnt = op_ptr->target_calls - op_ptr->results.good_calls;
754                 }
755             }
756         }
757
758         if (DEBUG_CHILD_RPC) {
759             (void) fprintf(stderr, "write: %d buffers\n", max_cnt);
760             (void) fflush(stderr);
761         }
762
763         /* make the call(s) now */
764         for (cur_cnt = 0; cur_cnt < max_cnt; cur_cnt++) {
765
766             /* capture length for possible dump */
767             Dump_length = fh_size(Cur_file_ptr);
768
769             sfs_gettime(&start);
770             rpc_stat = clnt_call(NFS_client, NFSPROC_WRITE,
771                                 xdr_write, (char *) &args,
772                                 xdr_write, (char *) &reply,
773                                 (Current_test_phase < Warmup_phase)
774                                      ? Nfs_timers[Init]
775                                      : Nfs_timers[op_ptr->call_class]);
776             sfs_gettime(&stop);
777             Cur_time = stop;
778
779             /* capture count and offset for possible dump */
780             Dump_count = args.data.data_len;
781             Dump_offset = args.offset;
782
783             if (rpc_stat == RPC_SUCCESS) {
784                 if (reply.status == NFS_OK) {
785                     Cur_file_ptr->state = Exists;
786                     Cur_file_ptr->attributes2 = reply.attrstat_u.attributes;
787                     Cur_file_ptr->size = fh_size(Cur_file_ptr);
788                     args.offset += size;
789
790                     if (DEBUG_CHILD_RPC) {
791                         (void) fprintf(stderr, "%s: WRITE %s %d bytes\n",
792                                            sfs_Myname, Cur_filename, size);
793                         (void) fflush(stderr);
794                     }
795                 } else {
796                     if (DEBUG_CHILD_ERROR) {
797                          (void) fprintf(stderr,
798                                 "%s: write call NFS error %s on file %d\n",
799                                 sfs_Myname, nfs2_strerror(reply.status),
800                                 Cur_file_ptr->unique_num);
801                     }
802                 }
803                 sfs_elapsedtime(op_ptr, &start, &stop);
804                 op_ptr->results.good_calls++;
805                 Ops[TOTAL].results.good_calls++;
806                 ret++;
807             } else {
808                 if (DEBUG_CHILD_ERROR) {
809                      (void) fprintf(stderr,
810                             "%s: write call RPC error %d on file %d\n",
811                             sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
812                 }
813                 op_ptr->results.bad_calls++;
814                 Ops[TOTAL].results.bad_calls++;
815             }
816         } /* for writing max_cnt packets */
817     } /* for buffers and fragments */
818     return(ret);
819
820 } /* op_write */
821
822
823 static int
824 op_create(void)
825 {
826     sfs_op_type         *op_ptr;                /* per operation info */
827     createargs          args;
828     diropres            reply;                  /* the reply */
829     enum clnt_stat      rpc_stat;               /* result from RPC call */
830     struct ladtime      start;
831     struct ladtime      stop;
832     int                 ret;                    /* ret val == call success */
833
834     op_ptr = &Ops[CREATE];
835     ret = 0;
836
837     /* set up the arguments */
838     args.attributes.mode = (0100000 | 0666);    /* 666 NFREG file */
839     args.attributes.uid = Cur_uid;
840     args.attributes.gid = Cur_gid;
841     args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
842     args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
843     args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
844     args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
845     args.attributes.size = 0;
846     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh2,
847                         NFS_FHSIZE);
848     args.where.name = Cur_filename;
849
850     /* make the call now */
851     sfs_gettime(&start);
852     rpc_stat = clnt_call(NFS_client, NFSPROC_CREATE,
853                         xdr_create, (char *) &args,
854                         xdr_create, (char *) &reply,
855                         (Current_test_phase < Warmup_phase)
856                                  ? Nfs_timers[Init]
857                                  : Nfs_timers[op_ptr->call_class]);
858     sfs_gettime(&stop);
859     Cur_time = stop;
860
861     if (rpc_stat == RPC_SUCCESS) {
862         if (reply.status == NFS_OK) {
863             Cur_file_ptr->state = Exists;
864             (void) memmove((char *) &Cur_file_ptr->fh2,
865                         (char *) &reply.diropres_u.diropres.file,
866                         NFS_FHSIZE);
867             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
868             Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
869             Cur_file_ptr->size = fh_size(Cur_file_ptr);
870         } else {
871             if (DEBUG_CHILD_ERROR) {
872                  (void) fprintf(stderr,
873                         "%s: create call NFS error %s on file %d\n",
874                         sfs_Myname, nfs2_strerror(reply.status),
875                         Cur_file_ptr->unique_num);
876             }
877         }
878         sfs_elapsedtime(op_ptr, &start, &stop);
879         op_ptr->results.good_calls++;
880         Ops[TOTAL].results.good_calls++;
881         ret++;
882     } else {
883         if (DEBUG_CHILD_ERROR) {
884              (void) fprintf(stderr, "%s: create call RPC error %d on file %d\n",
885                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
886         }
887         op_ptr->results.bad_calls++;
888         Ops[TOTAL].results.bad_calls++;
889     }
890     return(ret);
891
892 } /* op_create */
893
894
895 static int
896 op_remove(void)
897 {
898     sfs_op_type         *op_ptr;        /* per operation info */
899     diropargs           args;
900     nfsstat             reply;          /* the reply */
901     enum clnt_stat      rpc_stat;       /* result from RPC call */
902     struct ladtime      start;
903     struct ladtime      stop;
904     int                 ret;            /* ret val == call success */
905
906     op_ptr = &Ops[REMOVE];
907     ret = 0;
908
909     /* set up the arguments */
910     args.name = Cur_filename;
911     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
912                         NFS_FHSIZE);
913
914     /* make the call now */
915     sfs_gettime(&start);
916     rpc_stat = clnt_call(NFS_client, NFSPROC_REMOVE,
917                         xdr_remove, (char *) &args,
918                         xdr_remove, (char *) &reply,
919                         (Current_test_phase < Warmup_phase)
920                                  ? Nfs_timers[Init]
921                                  : Nfs_timers[op_ptr->call_class]);
922     sfs_gettime(&stop);
923     Cur_time = stop;
924
925     if (rpc_stat == RPC_SUCCESS) {
926         if (reply == NFS_OK) {
927             Cur_file_ptr->state = Nonexistent;
928         } else {
929             if (DEBUG_CHILD_ERROR) {
930                  (void) fprintf(stderr,
931                         "%s: remove call NFS error %s on file %d\n",
932                         sfs_Myname, nfs2_strerror(reply),
933                         Cur_file_ptr->unique_num);
934             }
935         }
936         sfs_elapsedtime(op_ptr, &start, &stop);
937         op_ptr->results.good_calls++;
938         Ops[TOTAL].results.good_calls++;
939         ret++;
940     } else {
941         if (DEBUG_CHILD_ERROR) {
942              (void) fprintf(stderr, "%s: remove call RPC error %d on file %d\n",
943                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
944         }
945         op_ptr->results.bad_calls++;
946         Ops[TOTAL].results.bad_calls++;
947     }
948     return(ret);
949
950 } /* op_remove */
951
952
953 static int
954 op_rename(void)
955 {
956     sfs_op_type         *op_ptr;                /* per operation info */
957     sfs_fh_type         *target_fileinfo_ptr;   /* target name */
958     renameargs          args;
959     nfsstat             reply;                  /* the reply */
960     enum clnt_stat      rpc_stat;               /* result from RPC call */
961     struct ladtime      start;
962     struct ladtime      stop;
963     int                 ret;                    /* ret val == call success */
964
965     op_ptr = &Ops[RENAME];
966     ret = 0;
967
968     /* set up the arguments */
969     (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh2,
970                         NFS_FHSIZE);
971     (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh2,
972                         NFS_FHSIZE);
973
974     target_fileinfo_ptr = randfh(RENAME, 0, 0, Nonexistent,
975                                  Sfs_non_io_file);
976
977     args.from.name = Cur_file_ptr->file_name;
978     (void) sprintf(target_fileinfo_ptr->file_name, Filespec,
979                    target_fileinfo_ptr->unique_num);
980     args.to.name = target_fileinfo_ptr->file_name;
981
982     /* make the call now */
983     sfs_gettime(&start);
984     rpc_stat = clnt_call(NFS_client, NFSPROC_RENAME,
985                         xdr_rename, (char *) &args,
986                         xdr_rename, (char *) &reply,
987                         (Current_test_phase < Warmup_phase)
988                                  ? Nfs_timers[Init]
989                                  : Nfs_timers[op_ptr->call_class]);
990     sfs_gettime(&stop);
991     Cur_time = stop;
992
993     if (rpc_stat == RPC_SUCCESS) {
994         if (reply == NFS_OK) {
995             target_fileinfo_ptr->state = Exists;
996             (void) memmove((char *) &target_fileinfo_ptr->fh2,
997                         (char *) &Cur_file_ptr->fh2,
998                         NFS_FHSIZE);
999             target_fileinfo_ptr->attributes2 = Cur_file_ptr->attributes2;
1000             target_fileinfo_ptr->size = Cur_file_ptr->size;
1001             Cur_file_ptr->state = Nonexistent;
1002         } else {
1003             if (DEBUG_CHILD_ERROR) {
1004                  (void) fprintf(stderr,
1005                         "%s: rename call NFS error %s on file %d\n",
1006                         sfs_Myname, nfs2_strerror(reply),
1007                         Cur_file_ptr->unique_num);
1008             }
1009         }
1010         sfs_elapsedtime(op_ptr, &start, &stop);
1011         op_ptr->results.good_calls++;
1012         Ops[TOTAL].results.good_calls++;
1013         ret++;
1014     } else {
1015         if (DEBUG_CHILD_ERROR) {
1016              (void) fprintf(stderr, "%s: rename call RPC error %d on file %d\n",
1017                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1018         }
1019         op_ptr->results.bad_calls++;
1020         Ops[TOTAL].results.bad_calls++;
1021     }
1022     return(ret);
1023
1024 } /* op_rename */
1025
1026
1027 static int
1028 op_link(void)
1029 {
1030     sfs_op_type         *op_ptr;                /* per operation info */
1031     sfs_fh_type         *target_fileinfo_ptr;   /* target */
1032     linkargs            args;
1033     nfsstat             reply;                  /* the reply */
1034     enum clnt_stat      rpc_stat;               /* result from RPC call */
1035     struct ladtime      start;
1036     struct ladtime      stop;
1037     int                 ret;                    /* ret val == call success */
1038
1039     op_ptr = &Ops[LINK];
1040     ret = 0;
1041
1042     /* set up the arguments */
1043     target_fileinfo_ptr = randfh(LINK, 0, 0, Exists, Sfs_non_io_file);
1044     (void) memmove((char *) &args.from, (char *) &target_fileinfo_ptr->fh2,
1045                         NFS_FHSIZE);
1046     (void) memmove((char *) &args.to.dir, (char *) &Cur_file_ptr->dir->fh2,
1047                         NFS_FHSIZE);
1048     args.to.name = Cur_filename;
1049
1050     /* make the call now */
1051     sfs_gettime(&start);
1052     rpc_stat = clnt_call(NFS_client, NFSPROC_LINK,
1053                         xdr_link, (char *) &args,
1054                         xdr_link, (char *) &reply,
1055                         (Current_test_phase < Warmup_phase)
1056                                  ? Nfs_timers[Init]
1057                                  : Nfs_timers[op_ptr->call_class]);
1058     sfs_gettime(&stop);
1059     Cur_time = stop;
1060
1061     if (rpc_stat == RPC_SUCCESS) {
1062         if (reply == NFS_OK) {
1063             Cur_file_ptr->state = Exists;
1064             (void) memmove((char *) &Cur_file_ptr->fh2,
1065                         (char *) &target_fileinfo_ptr->fh2, NFS_FHSIZE);
1066             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1067             target_fileinfo_ptr->attributes2.nlink++;
1068             Cur_file_ptr->attributes2 = target_fileinfo_ptr->attributes2;
1069             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1070         } else {
1071             if (DEBUG_CHILD_ERROR) {
1072                  (void) fprintf(stderr,
1073                         "%s: link call NFS error %s on file %d\n",
1074                         sfs_Myname, nfs2_strerror(reply),
1075                         Cur_file_ptr->unique_num);
1076             }
1077         }
1078         sfs_elapsedtime(op_ptr, &start, &stop);
1079         op_ptr->results.good_calls++;
1080         Ops[TOTAL].results.good_calls++;
1081         ret++;
1082     } else {
1083         if (DEBUG_CHILD_ERROR) {
1084              (void) fprintf(stderr, "%s: link call RPC error %d on file %d\n",
1085                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1086         }
1087         op_ptr->results.bad_calls++;
1088         Ops[TOTAL].results.bad_calls++;
1089     }
1090     return(ret);
1091
1092 } /* op_link */
1093
1094
1095 static int
1096 op_symlink(void)
1097 {
1098     sfs_op_type         *op_ptr;                /* per operation info */
1099     sfs_fh_type         *target_fileinfo_ptr;   /* target file */
1100     symlinkargs         args;
1101     nfsstat             reply;                  /* the reply */
1102     char                sym_data[NFS_MAXPATHLEN];       /* symlink data */
1103     enum clnt_stat      rpc_stat;               /* result from RPC call */
1104     struct ladtime      start;
1105     struct ladtime      stop;
1106     int                 ret;                    /* ret val == call success */
1107
1108     op_ptr = &Ops[SYMLINK];
1109     ret = 0;
1110
1111     /* set up the arguments */
1112     target_fileinfo_ptr = randfh(SYMLINK, 0, 0, Exists, Sfs_non_io_file);
1113     (void) memmove((char *) &args.from.dir, (char *) &Cur_file_ptr->dir->fh2,
1114                         NFS_FHSIZE);
1115     args.from.name = Cur_filename;
1116
1117     (void) strcpy(sym_data, "./");
1118     (void) strcat(sym_data, target_fileinfo_ptr->file_name);
1119     args.attributes.size = strlen(sym_data);
1120     args.to = sym_data;
1121
1122     args.attributes.mode = (0120000 | 0777);
1123     args.attributes.uid = Cur_uid;
1124     args.attributes.gid = Cur_gid;
1125     args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
1126     args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
1127     args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
1128     args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
1129
1130     /* make the call now */
1131     sfs_gettime(&start);
1132     rpc_stat = clnt_call(NFS_client, NFSPROC_SYMLINK,
1133                         xdr_symlink, (char *) &args,
1134                         xdr_symlink, (char *) &reply,
1135                         ((int)Current_test_phase < (int)Warmup_phase)
1136                                  ? Nfs_timers[Init]
1137                                  : Nfs_timers[op_ptr->call_class]);
1138     sfs_gettime(&stop);
1139     Cur_time = stop;
1140
1141     if (rpc_stat == RPC_SUCCESS) {
1142         if (reply == NFS_OK) {
1143             /*
1144              * SYMLINK doesn't return a fh. If we try to
1145              * access this symlink (eg, remove(), readlink())
1146              * before we do a lookup, we won't have a fh to use.
1147              * So, we do a lookup call here.
1148              * If it fails, we fill in what we can.
1149              */
1150             Cur_file_ptr->state = Exists;
1151             if (op_lookup() == 0) {
1152                 (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1153                 Cur_file_ptr->attributes2.type = NFLNK;
1154                 Cur_file_ptr->attributes2.mode = (0120000|0777);
1155                 Cur_file_ptr->attributes2.uid = Cur_uid;
1156                 Cur_file_ptr->attributes2.gid = Cur_gid;
1157                 Cur_file_ptr->attributes2.atime.seconds =(unsigned int)Cur_time.esec;
1158                 Cur_file_ptr->attributes2.atime.useconds=(unsigned int)Cur_time.usec;
1159                 Cur_file_ptr->attributes2.mtime = Cur_file_ptr->attributes2.atime;
1160             } else
1161                 ret++;
1162         } else {
1163             if (DEBUG_CHILD_ERROR) {
1164                  (void) fprintf(stderr,
1165                         "%s: symlink call NFS error %s on file %d\n",
1166                         sfs_Myname, nfs2_strerror(reply),
1167                         Cur_file_ptr->unique_num);
1168             }
1169         }
1170         sfs_elapsedtime(op_ptr, &start, &stop);
1171         op_ptr->results.good_calls++;
1172         Ops[TOTAL].results.good_calls++;
1173         ret++;
1174     } else {
1175         if (DEBUG_CHILD_ERROR) {
1176              (void) fprintf(stderr, "%s: symlink call RPC error %d on file %d\n",
1177                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1178         }
1179         op_ptr->results.bad_calls++;
1180         Ops[TOTAL].results.bad_calls++;
1181     }
1182     return(ret);
1183
1184 } /* op_symlink */
1185
1186
1187 static int
1188 op_mkdir(void)
1189 {
1190     sfs_op_type         *op_ptr;                /* per operation info */
1191     mkdirargs           args;
1192     diropres            reply;                  /* the reply */
1193     enum clnt_stat      rpc_stat;               /* result from RPC call */
1194     struct ladtime      start;
1195     struct ladtime      stop;
1196     int                 ret;                    /* ret val == call success */
1197
1198     op_ptr = &Ops[MKDIR];
1199     ret = 0;
1200
1201     /* set up the arguments */
1202     args.attributes.mode = (NFSMODE_DIR | 0777);
1203     args.attributes.uid = Cur_uid;
1204     args.attributes.gid = Cur_gid;
1205     args.attributes.size = (unsigned int) 512;
1206     args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
1207     args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
1208     args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
1209     args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
1210     (void) memmove((char *) &args.where.dir, (char *) &Cur_file_ptr->dir->fh2,
1211                         NFS_FHSIZE);
1212     args.where.name = Cur_filename;
1213
1214     /* make the call now */
1215     sfs_gettime(&start);
1216     rpc_stat = clnt_call(NFS_client, NFSPROC_MKDIR,
1217                         xdr_mkdir, (char *) &args,
1218                         xdr_mkdir, (char *) &reply,
1219                         (Current_test_phase < Warmup_phase)
1220                                  ? Nfs_timers[Init]
1221                                  : Nfs_timers[op_ptr->call_class]);
1222     sfs_gettime(&stop);
1223     Cur_time = stop;
1224
1225     if (rpc_stat == RPC_SUCCESS) {
1226         if (reply.status == NFS_OK) {
1227             Cur_file_ptr->state = Empty_dir;
1228             (void) memmove((char *) &Cur_file_ptr->fh2,
1229                         (char *) &reply.diropres_u.diropres.file,
1230                         NFS_FHSIZE);
1231             (void) strcpy(Cur_file_ptr->file_name, Cur_filename);
1232             Cur_file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
1233             Cur_file_ptr->size = fh_size(Cur_file_ptr);
1234         } else {
1235             if (DEBUG_CHILD_ERROR) {
1236                  (void) fprintf(stderr,
1237                         "%s: mkdir call NFS error %s on file %d\n",
1238                         sfs_Myname, nfs2_strerror(reply.status),
1239                         Cur_file_ptr->unique_num);
1240             }
1241         }
1242         sfs_elapsedtime(op_ptr, &start, &stop);
1243         op_ptr->results.good_calls++;
1244         Ops[TOTAL].results.good_calls++;
1245         ret++;
1246     } else {
1247         if (DEBUG_CHILD_ERROR) {
1248              (void) fprintf(stderr, "%s: mkdir call RPC error %d on file %d\n",
1249                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1250         }
1251         op_ptr->results.bad_calls++;
1252         Ops[TOTAL].results.bad_calls++;
1253     }
1254     return(ret);
1255
1256 } /* op_mkdir */
1257
1258
1259 static int
1260 op_rmdir(void)
1261 {
1262     sfs_op_type         *op_ptr;        /* per operation info */
1263     diropargs           args;
1264     nfsstat             reply;          /* the reply */
1265     enum clnt_stat      rpc_stat;       /* result from RPC call */
1266     struct ladtime      start;
1267     struct ladtime      stop;
1268     int                 ret;            /* ret val == call success */
1269
1270     op_ptr = &Ops[RMDIR];
1271     ret = 0;
1272
1273     if (Cur_file_ptr->state != Empty_dir) {
1274              (void) fprintf(stderr, "%s: Attempting to remove non-Empty_dir %d\n",
1275                     sfs_Myname, Cur_file_ptr->unique_num);
1276     }
1277
1278     /* set up the arguments */
1279     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
1280                         NFS_FHSIZE);
1281     args.name = Cur_file_ptr->file_name;
1282
1283     /* make the call now */
1284     sfs_gettime(&start);
1285     rpc_stat = clnt_call(NFS_client, NFSPROC_RMDIR,
1286                         xdr_rmdir, (char *) &args,
1287                         xdr_rmdir, (char *) &reply,
1288                         (Current_test_phase < Warmup_phase)
1289                                  ? Nfs_timers[Init]
1290                                  : Nfs_timers[op_ptr->call_class]);
1291     sfs_gettime(&stop);
1292     Cur_time = stop;
1293
1294     if (rpc_stat == RPC_SUCCESS) {
1295         if (reply == NFS_OK) {
1296             Cur_file_ptr->state = Nonexistent;
1297         } else {
1298             if (DEBUG_CHILD_ERROR) {
1299                  (void) fprintf(stderr,
1300                         "%s: rmdir call NFS error %s on file %d\n",
1301                         sfs_Myname, nfs2_strerror(reply),
1302                         Cur_file_ptr->unique_num);
1303             }
1304         }
1305         sfs_elapsedtime(op_ptr, &start, &stop);
1306         op_ptr->results.good_calls++;
1307         Ops[TOTAL].results.good_calls++;
1308         ret++;
1309     } else {
1310         if (DEBUG_CHILD_ERROR) {
1311              (void) fprintf(stderr, "%s: rmdir call RPC error %d on file %d\n",
1312                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1313         }
1314         op_ptr->results.bad_calls++;
1315         Ops[TOTAL].results.bad_calls++;
1316     }
1317     return(ret);
1318
1319 } /* op_rmdir */
1320
1321
1322 static int
1323 op_readdir(void)
1324 {
1325     sfs_op_type         *op_ptr;                /* per operation info */
1326     readdirargs         args;
1327     readdirres          reply;                  /* the reply */
1328     enum clnt_stat      rpc_stat;               /* result from RPC call */
1329     uint_t              i;
1330     struct ladtime      start;
1331     struct ladtime      stop;
1332     int                 ret;                    /* ret val == call success */
1333     nfscookie           cookie;
1334     bool_t              hit_eof;
1335         /* arbitrary fixed ceiling */
1336     int                 entry_cnt = SFS_MAXDIRENTS;
1337         /* array of entries */
1338     entry               entry_stream[SFS_MAXDIRENTS];
1339     entry               *entry_ptr;             /* ptr to the dir entry */
1340
1341     char        name[SFS_MAXNAMLEN];
1342         /* array of dir names */
1343     char        name_stream[SFS_MAXDIRENTS * SFS_MAXNAMLEN];
1344
1345
1346     /*
1347      * 1) need some measure of how many entries are in a directory
1348      * currently, we assume SFS_MAXDIRENTS - it should be random
1349      * from 0 to MAX for a large MAX we should pre-allocate a buffer for the
1350      * returned directory names.
1351      * 2) need some measure of how many directory entries to read
1352      * during each readdir() call.  Again, we assume SFS_MAXDIRENTS.
1353      */
1354
1355     op_ptr = &Ops[READDIR];
1356     ret = 0;
1357
1358     /* set up the arguments */
1359     (void) memmove((char *) &args.dir, (char *) &Cur_file_ptr->dir->fh2,
1360                         NFS_FHSIZE);
1361     (void) memset((char *) args.cookie, '\0', NFS_COOKIESIZE);
1362     args.count = DEFAULT_MAX_BUFSIZE;
1363
1364     /* Have lower layers fill in the data directly.  */
1365     reply.readdirres_u.reply.max_entries = entry_cnt;
1366     reply.readdirres_u.reply.entries = entry_stream;
1367     for (i = 0; i < entry_cnt; i++) {
1368         entry_stream[i].name = &name_stream[i * SFS_MAXNAMLEN];
1369     }
1370
1371     /* make the call now */
1372     sfs_gettime(&start);
1373     rpc_stat = clnt_call(NFS_client, NFSPROC_READDIR,
1374                         xdr_readdir, (char *) &args,
1375                         xdr_readdir, (char *) &reply,
1376                         (Current_test_phase < Warmup_phase)
1377                                  ? Nfs_timers[Init]
1378                                  : Nfs_timers[op_ptr->call_class]);
1379     sfs_gettime(&stop);
1380     Cur_time = stop;
1381
1382     if (rpc_stat == RPC_SUCCESS) {
1383         if (reply.status == NFS_OK) {
1384
1385             if (DEBUG_CHILD_RPC) {
1386                 hit_eof = reply.readdirres_u.reply.eof;
1387                 entry_cnt = reply.readdirres_u.reply.max_entries;
1388                 entry_ptr = reply.readdirres_u.reply.entries;
1389                 for (i = 0; i < entry_cnt; i++) {
1390                     entry_ptr->name[entry_ptr->name_len] ='\0';
1391                     (void) strcpy(name, entry_ptr->name);
1392                     (void) memmove((char *) cookie,
1393                                         (char *) entry_ptr->cookie,
1394                                         NFS_COOKIESIZE);
1395                     (void) fprintf(stderr, "%s:READDIR (eof=%d) entry %s\n",
1396                                         sfs_Myname, hit_eof, name);
1397                     entry_ptr++;
1398                 }
1399                 (void) fflush(stderr);
1400             }
1401         } else {
1402             if (DEBUG_CHILD_ERROR) {
1403                  (void) fprintf(stderr,
1404                         "%s: readdir call NFS error %s on file %d\n",
1405                         sfs_Myname, nfs2_strerror(reply.status),
1406                         Cur_file_ptr->unique_num);
1407             }
1408         }
1409         sfs_elapsedtime(op_ptr, &start, &stop);
1410         op_ptr->results.good_calls++;
1411         Ops[TOTAL].results.good_calls++;
1412         ret++;
1413     } else {
1414         if (DEBUG_CHILD_ERROR) {
1415              (void) fprintf(stderr, "%s: readdir call RPC error %d on file %d\n",
1416                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1417         }
1418         op_ptr->results.bad_calls++;
1419         Ops[TOTAL].results.bad_calls++;
1420     }
1421     return(ret);
1422
1423 } /* op_readdir */
1424
1425
1426 /* Beware - op_statfs() collides w/ some other name, use op_fsstat() */
1427 static int
1428 op_fsstat(void)
1429 {
1430     sfs_op_type         *op_ptr;        /* per operation info */
1431     fhandle_t           fh;
1432     statfsres           reply;          /* the reply */
1433     enum clnt_stat      rpc_stat;       /* result from RPC call */
1434     struct ladtime      start;
1435     struct ladtime      stop;
1436     int                 ret;            /* ret val == call success */
1437
1438     op_ptr = &Ops[FSSTAT];
1439     ret = 0;
1440
1441     /* set up the arguments */
1442     (void) memmove((char *) &fh, (char *) &Cur_file_ptr->fh2,
1443                         NFS_FHSIZE);
1444
1445     /* make the call */
1446     sfs_gettime(&start);
1447     rpc_stat = clnt_call(NFS_client, NFSPROC_STATFS,
1448                         xdr_statfs, (char *) &fh,
1449                         xdr_statfs, (char *) &reply,
1450                         (Current_test_phase < Warmup_phase)
1451                                  ? Nfs_timers[Init]
1452                                  : Nfs_timers[op_ptr->call_class]);
1453     sfs_gettime(&stop);
1454     Cur_time = stop;
1455
1456     if (rpc_stat == RPC_SUCCESS) {
1457         sfs_elapsedtime(op_ptr, &start, &stop);
1458         op_ptr->results.good_calls++;
1459         Ops[TOTAL].results.good_calls++;
1460         ret++;
1461     } else {
1462         if (DEBUG_CHILD_ERROR) {
1463              (void) fprintf(stderr, "%s: fsstat call RPC error %d on file %d\n",
1464                     sfs_Myname, rpc_stat, Cur_file_ptr->unique_num);
1465         }
1466         op_ptr->results.bad_calls++;
1467         Ops[TOTAL].results.bad_calls++;
1468     }
1469     return(ret);
1470
1471 } /* op_fsstat */
1472
1473
1474 /*
1475  * These are a set of reliable functions used by the initialization code.
1476  */
1477
1478 #define LAD_RETRIABLE(stat) (((stat) == RPC_TIMEDOUT) || ((stat) == RPC_CANTDECODERES))
1479
1480 /*
1481  * Reliably lookup a file in the current directory
1482  * Return:
1483  *      -1      RPC error
1484  *      1       File doesn't exist
1485  *      0       File exists
1486  */
1487 int
1488 lad_lookup(sfs_fh_type *file_ptr, char *name)
1489 {
1490     diropargs           args;
1491     diropres            reply;          /* the reply */
1492     enum clnt_stat      rpc_stat;       /* result from RPC call */
1493
1494     if (DEBUG_CHILD_RPC) {
1495         (void) fprintf(stderr, "%s:lad_lookup: %lx[%lx] %s\n", sfs_Myname,
1496                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1497         (void) fflush(stderr);
1498     }
1499
1500     /* CONSTCOND */
1501     while (1) {
1502         /* set up the arguments */
1503         (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
1504                         NFS_FHSIZE);
1505         args.name = name;
1506
1507         /* make the call */
1508         rpc_stat = clnt_call(NFS_client, NFSPROC_LOOKUP,
1509                         xdr_lookup, (char *) &args,
1510                         xdr_lookup, (char *) &reply,
1511                         Nfs_timers[Init]);
1512
1513         if (rpc_stat == RPC_SUCCESS) 
1514                 break;
1515         if (rpc_stat != RPC_TIMEDOUT) {
1516                 (void) fprintf(stderr, "lad_lookup(%s) RPC call failed : %s\n",
1517                                 name, clnt_sperrno(rpc_stat));
1518         }
1519         if (!LAD_RETRIABLE(rpc_stat)) {
1520                 return(-1);
1521         }
1522     }
1523
1524     if (reply.status == NFSERR_NOENT) {
1525         return(1);
1526     }
1527
1528     if (reply.status != NFS_OK) {
1529         (void) fprintf(stderr, "lad_lookup(%s) NFS call failed : %s\n",
1530                         name, nfs2_strerror(reply.status));
1531         return(-1);
1532     }
1533
1534     file_ptr->state = Exists;
1535     (void) memmove((char *) &file_ptr->fh2,
1536                         (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
1537     (void) strcpy(file_ptr->file_name, name);
1538     file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
1539     file_ptr->size = fh_size(file_ptr);
1540
1541     return(0);
1542 }
1543
1544 /*
1545  * Reliably remove a file in the current directory
1546  */
1547 int
1548 lad_remove(sfs_fh_type *file_ptr, char *name)
1549 {
1550     diropargs           args;
1551     nfsstat             reply;          /* the reply */
1552     enum clnt_stat      rpc_stat;       /* result from RPC call */
1553     int                 retried = 0;
1554
1555     if (DEBUG_CHILD_RPC) {
1556         (void) fprintf(stderr, "%s:lad_remove: %lx[%lx] %s\n", sfs_Myname,
1557                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1558         (void) fflush(stderr);
1559     }
1560
1561     /*
1562      * This function presumes that the file name does exist
1563      */
1564     if (file_ptr->attributes2.type == NFDIR)
1565         return (lad_rmdir(file_ptr, name));
1566
1567     /* CONSTCOND */
1568     while (1) {
1569         /* set up the arguments */
1570         args.name = name;
1571         (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
1572                         NFS_FHSIZE);
1573
1574         /* make the call now */
1575         rpc_stat = clnt_call(NFS_client, NFSPROC_REMOVE,
1576                         xdr_remove, (char *) &args,
1577                         xdr_remove, (char *) &reply,
1578                         Nfs_timers[Init]);
1579
1580         if (rpc_stat == RPC_SUCCESS) 
1581                 break;
1582         if (rpc_stat != RPC_TIMEDOUT) {
1583                 (void) fprintf(stderr, "lad_remove(%s) RPC call failed : %s\n",
1584                                 name, clnt_sperrno(rpc_stat));
1585         }
1586         if (!LAD_RETRIABLE(rpc_stat)) {
1587                 return(-1);
1588         }
1589         retried++;
1590     }
1591
1592     if (reply != NFS_OK) {
1593         if (reply != NFSERR_NOENT || !retried) {
1594             (void) fprintf(stderr, "lad_remove(%s) NFS call failed : %s\n",
1595                         name, nfs2_strerror(reply));
1596             return(-1);
1597         }
1598     }
1599
1600     file_ptr->state = Nonexistent;
1601
1602     return(0);
1603 }
1604
1605 /*
1606  * Reliably remove a directory in the current directory
1607  */
1608 int
1609 lad_rmdir(sfs_fh_type *file_ptr, char *name)
1610 {
1611     diropargs           args;
1612     nfsstat             reply;          /* the reply */
1613     enum clnt_stat      rpc_stat;       /* result from RPC call */
1614     int                 retried = 0;
1615
1616     if (DEBUG_CHILD_RPC) {
1617         (void) fprintf(stderr, "%s: lad_rmdir: %lx[%lx] %s\n", sfs_Myname,
1618                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1619         (void) fflush(stderr);
1620     }
1621
1622     /*
1623      * This function presumes that the file name does exist and the directory
1624      * is empty.
1625      */
1626     if (file_ptr->attributes2.type != NFDIR)
1627         return (lad_remove(file_ptr, name));
1628
1629     /* CONSTCOND */
1630     while (1) {
1631         /* set up the arguments */
1632         args.name = name;
1633         (void) memmove((char *) &args.dir, (char *) &file_ptr->dir->fh2,
1634                         NFS_FHSIZE);
1635
1636         /* make the call now */
1637         rpc_stat = clnt_call(NFS_client, NFSPROC_RMDIR,
1638                         xdr_remove, (char *) &args,
1639                         xdr_remove, (char *) &reply,
1640                         Nfs_timers[Init]);
1641
1642         if (rpc_stat == RPC_SUCCESS) 
1643                 break;
1644         if (rpc_stat != RPC_TIMEDOUT) {
1645                 (void) fprintf(stderr, "lad_rmdir(%s) RPC call failed : %s\n",
1646                                 name, clnt_sperrno(rpc_stat));
1647         }
1648         if (!LAD_RETRIABLE(rpc_stat)) {
1649                 return(-1);
1650         }
1651         retried++;
1652     }
1653
1654     if (reply != NFS_OK) {
1655         if (reply != NFSERR_NOENT || !retried) {
1656             (void) fprintf(stderr, "lad_rmdir(%s) NFS call failed : %s\n",
1657                         name, nfs2_strerror(reply));
1658             return(-1);
1659         }
1660     }
1661
1662     file_ptr->state = Nonexistent;
1663
1664     return(0);
1665 }
1666
1667 /*
1668  * Reliably create a symlink in the current directory
1669  */
1670 int
1671 lad_symlink(sfs_fh_type *file_ptr, char *target, char *name)
1672 {
1673     symlinkargs         args;
1674     nfsstat             reply;                  /* the reply */
1675     char                sym_data[NFS_MAXPATHLEN];       /* symlink data */
1676     enum clnt_stat      rpc_stat;               /* result from RPC call */
1677     int                 retried = 0;
1678
1679     if (DEBUG_CHILD_RPC) {
1680         (void) fprintf(stderr, "%s:lad_symlink: %lx %s -> %s\n", sfs_Myname,
1681                         (int32_t) file_ptr, name, target);
1682         (void) fflush(stderr);
1683     }
1684
1685     /*
1686      * This function presumes that the file name does not already exist
1687      */
1688     /* CONSTCOND */
1689     while (1) {
1690         /* set up the arguments */
1691         (void) memmove((char *) &args.from.dir, (char *) &file_ptr->dir->fh2,
1692                         NFS_FHSIZE);
1693         args.from.name = name;
1694
1695         (void) strcpy(sym_data, "./");
1696         (void) strcat(sym_data, target);
1697         args.attributes.size = strlen(sym_data);
1698         args.to = sym_data;
1699
1700         args.attributes.mode = (0120000 | 0777);
1701         args.attributes.uid = Cur_uid;
1702         args.attributes.gid = Cur_gid;
1703         args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
1704         args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
1705         args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
1706         args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
1707
1708         /* make the call now */
1709         rpc_stat = clnt_call(NFS_client, NFSPROC_SYMLINK,
1710                         xdr_symlink, (char *) &args,
1711                         xdr_symlink, (char *) &reply,
1712                         Nfs_timers[Init]);
1713         if (rpc_stat == RPC_SUCCESS) 
1714                 break;
1715         if (rpc_stat != RPC_TIMEDOUT) {
1716                 (void) fprintf(stderr, "lad_symlink(%s) RPC call failed : %s\n",
1717                                 name, clnt_sperrno(rpc_stat));
1718         }
1719         if (!LAD_RETRIABLE(rpc_stat)) {
1720                 return(-1);
1721         }
1722         retried++;
1723     }
1724
1725     if (reply != NFS_OK) {
1726         if (reply != NFSERR_EXIST || !retried) {
1727             (void) fprintf(stderr, "lad_symlink(%s, %s) NFS call failed : %s\n",
1728                         target, name, nfs2_strerror(reply));
1729             return(-1);
1730         }
1731     }
1732
1733     /*
1734      * SYMLINK doesn't return a fh. If we try to
1735      * access this symlink (eg, remove(), readlink())
1736      * before we do a lookup, we won't have a fh to use.
1737      * So, we do a lookup call here.
1738      * If it fails, we fill in what we can.
1739      */
1740     return (lad_lookup(file_ptr, name));
1741 }
1742
1743 /*
1744  * Reliably create a directory in the current directory
1745  */
1746 int
1747 lad_mkdir(sfs_fh_type *file_ptr, char *name)
1748 {
1749     mkdirargs           args;
1750     diropres            reply;                  /* the reply */
1751     enum clnt_stat      rpc_stat;               /* result from RPC call */
1752     int                 retried = 0;
1753
1754     if (DEBUG_CHILD_RPC) {
1755         (void) fprintf(stderr, "%s:lad_mkdir: %lx[%lx] %s\n", sfs_Myname,
1756                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1757         (void) fflush(stderr);
1758     }
1759
1760     /*
1761      * This function presumes that the file name does not already exist
1762      */
1763     /* CONSTCOND */
1764     while (1) {
1765         /* set up the arguments */
1766         args.attributes.mode = (NFSMODE_DIR | 0777);
1767         args.attributes.uid = Cur_uid;
1768         args.attributes.gid = Cur_gid;
1769         args.attributes.size = (unsigned int) 512;
1770         args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
1771         args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
1772         args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
1773         args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
1774         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh2,
1775                         NFS_FHSIZE);
1776         args.where.name = name;
1777
1778         /* make the call now */
1779         rpc_stat = clnt_call(NFS_client, NFSPROC_MKDIR,
1780                         xdr_mkdir, (char *) &args,
1781                         xdr_mkdir, (char *) &reply,
1782                         Nfs_timers[Init]);
1783
1784         if (rpc_stat == RPC_SUCCESS) 
1785                 break;
1786         if (rpc_stat != RPC_TIMEDOUT) {
1787                 (void) fprintf(stderr, "lad_mkdir(%s) RPC call failed : %s\n",
1788                                 name, clnt_sperrno(rpc_stat));
1789         }
1790         if (!LAD_RETRIABLE(rpc_stat)) {
1791                 return(-1);
1792         }
1793         retried++;
1794     }
1795
1796     if (!retried && reply.status == NFSERR_EXIST)
1797         return(1);
1798
1799     if (reply.status != NFS_OK) {
1800         if (reply.status != NFSERR_EXIST || !retried) {
1801             (void) fprintf(stderr, "lad_mkdir(%s) NFS call failed : %s\n",
1802                         name, nfs2_strerror(reply.status));
1803             return(-1);
1804         }
1805         /*
1806          * If the first mkdir suceeded but the reply as dropped and
1807          * was retransmitted, we still need to lookup the attributes
1808          */
1809         if (lad_lookup(file_ptr, name))
1810            return (-1);
1811     } else {
1812         (void) memmove((char *) &file_ptr->fh2,
1813                         (char *) &reply.diropres_u.diropres.file,
1814                         NFS_FHSIZE);
1815         (void) strcpy(file_ptr->file_name, name);
1816         file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
1817         file_ptr->size = fh_size(file_ptr);
1818     }
1819     file_ptr->state = Empty_dir;
1820
1821     return(0);
1822 }
1823
1824 /*
1825  * Reliably write a file in the current directory
1826  */
1827 int
1828 lad_write(sfs_fh_type *file_ptr, int32_t offset, int32_t length)
1829 {
1830     static char                 *buf = NULL;    /* the data buffer */
1831     int32_t                     size;           /* size of data write */
1832     int32_t                     cur_cnt;
1833     writeargs                   args;
1834     attrstat                    reply;          /* the reply */
1835     enum clnt_stat              rpc_stat;       /* result from RPC call */
1836
1837     if (DEBUG_CHILD_RPC) {
1838         (void) fprintf(stderr, "%s:lad_write: %lx[%lx] %ld %ld\n",
1839                         sfs_Myname, (int32_t) file_ptr, (int32_t) file_ptr->dir,
1840                         offset, length);
1841         (void) fflush(stderr);
1842     }
1843
1844     /*
1845      * This function presumes that the file name does exist
1846      * Initialize write buffer to known value
1847      */
1848     if (buf == NULL) {
1849         buf = init_write_buffer();
1850     }
1851
1852     /* set up the arguments */
1853     (void) memmove((char *) &args.file, (char *) &file_ptr->fh2,
1854                         NFS_FHSIZE);
1855     args.beginoffset = 0;       /* unused */
1856     args.offset = offset;
1857
1858     size = Bytes_per_block;
1859     for (cur_cnt = 0; cur_cnt < length; cur_cnt += size) {
1860         if ((cur_cnt + size) > length)
1861                 size = length - cur_cnt;
1862
1863         if (size == 0)
1864             break;
1865
1866         args.totalcount = size; /* unused */
1867         args.data.data_len = size;
1868         args.data.data_val = buf;
1869
1870         /* make the call now */
1871         /* CONSTCOND */
1872         while (1) {
1873             rpc_stat = clnt_call(NFS_client, NFSPROC_WRITE,
1874                                 xdr_write, (char *) &args,
1875                                 xdr_write, (char *) &reply,
1876                                 Nfs_timers[Init]);
1877
1878             if (rpc_stat == RPC_SUCCESS) 
1879                 break;
1880             if (rpc_stat != RPC_TIMEDOUT) {
1881                 (void) fprintf(stderr, "lad_write() RPC call failed : %s\n",
1882                                 clnt_sperrno(rpc_stat));
1883             }
1884             if (!LAD_RETRIABLE(rpc_stat)) {
1885                 return(-1);
1886             }
1887         }
1888         if (reply.status != NFS_OK) {
1889             (void) fprintf(stderr, "lad_write() NFS call failed : %s\n",
1890                         nfs2_strerror(reply.status));
1891             return(-1);
1892         }
1893         file_ptr->state = Exists;
1894         file_ptr->attributes2 = reply.attrstat_u.attributes;
1895         file_ptr->size = fh_size(file_ptr);
1896         args.offset += size;
1897     }
1898     return(0);
1899 }
1900
1901 /*
1902  * Reliably create a file in the current directory
1903  */
1904 int
1905 lad_create(sfs_fh_type *file_ptr, char *name)
1906 {
1907     createargs          args;
1908     diropres            reply;                  /* the reply */
1909     enum clnt_stat      rpc_stat;               /* result from RPC call */
1910     int                 retried = 0;
1911
1912     if (DEBUG_CHILD_RPC) {
1913         (void) fprintf(stderr, "%s:lad_create: %lx[%lx] %s\n", sfs_Myname,
1914                         (int32_t) file_ptr, (int32_t) file_ptr->dir, name);
1915         (void) fflush(stderr);
1916     }
1917
1918     /*
1919      * This function presumes that the file name does not already exist
1920      */
1921     /* CONSTCOND */
1922     while (1) {
1923         /* set up the arguments */
1924         args.attributes.mode = (0100000 | 0666);        /* 666 NFREG file */
1925         args.attributes.uid = Cur_uid;
1926         args.attributes.gid = Cur_gid;
1927         args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
1928         args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
1929         args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
1930         args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
1931         args.attributes.size = 0;
1932         (void) memmove((char *) &args.where.dir, (char *) &file_ptr->dir->fh2,
1933                         NFS_FHSIZE);
1934         args.where.name = name;
1935
1936         /* make the call now */
1937         rpc_stat = clnt_call(NFS_client, NFSPROC_CREATE,
1938                         xdr_create, (char *) &args,
1939                         xdr_create, (char *) &reply,
1940                         Nfs_timers[Init]);
1941
1942         if (rpc_stat == RPC_SUCCESS) 
1943                 break;
1944         if (rpc_stat != RPC_TIMEDOUT) {
1945                 (void) fprintf(stderr, "lad_create(%s) RPC call failed : %s\n",
1946                                 name, clnt_sperrno(rpc_stat));
1947         }
1948         if (!LAD_RETRIABLE(rpc_stat)) {
1949                 return(-1);
1950         }
1951         retried++;
1952     }
1953
1954     if (!retried && reply.status == NFSERR_EXIST) {
1955         return(1);
1956     }
1957
1958     if (reply.status != NFS_OK) {
1959         if (reply.status != NFSERR_EXIST || !retried) {
1960             (void) fprintf(stderr, "lad_create(%s) NFS call failed : %s\n",
1961                         name, nfs2_strerror(reply.status));
1962             return(-1);
1963         }
1964         /*
1965          * If the first create suceeded but the reply as dropped and
1966          * was retransmitted, we still need to lookup the attributes
1967          */
1968         if (lad_lookup(file_ptr, name))
1969            return (-1);
1970     } else {
1971         (void) memmove((char *) &file_ptr->fh2,
1972                         (char *) &reply.diropres_u.diropres.file, NFS_FHSIZE);
1973         (void) strcpy(file_ptr->file_name, name);
1974         file_ptr->attributes2 = reply.diropres_u.diropres.attributes;
1975         file_ptr->size = fh_size(file_ptr);
1976     }
1977
1978     file_ptr->state = Exists;
1979     /*
1980      * Directories are created as Empty_dir, when a file is created it
1981      * becomes an Exists.
1982      */
1983     file_ptr->dir->state = Exists;
1984
1985     return(0);
1986 }
1987
1988 /*
1989  * Reliably set the size of a file in the current directory
1990  */
1991 int
1992 lad_truncate(sfs_fh_type *file_ptr, int32_t size)
1993 {
1994     sattrargs           args;
1995     attrstat            reply;          /* the reply */
1996     enum clnt_stat      rpc_stat;       /* result from RPC call */
1997
1998     if (DEBUG_CHILD_RPC) {
1999         (void) fprintf(stderr, "%s:lad_truncate: %lx[%lx] %ld\n", sfs_Myname,
2000                         (int32_t) file_ptr, (int32_t) file_ptr->dir, size);
2001         (void) fflush(stderr);
2002     }
2003
2004     /*
2005      * This function presumes that the file name already exists
2006      */
2007     /* CONSTCOND */
2008     while (1) {
2009         /*
2010          * set up the arguments
2011          * Set the mode and times as well
2012          */
2013         args.attributes.mode = 0666;
2014         args.attributes.uid = (unsigned int) -1;
2015         args.attributes.gid = (unsigned int) -1;
2016         args.attributes.size = (unsigned int) -1;
2017         args.attributes.atime.seconds = (unsigned int) Cur_time.esec;
2018         args.attributes.atime.useconds = (unsigned int) Cur_time.usec;
2019         args.attributes.mtime.seconds = (unsigned int) Cur_time.esec;
2020         args.attributes.mtime.useconds = (unsigned int) Cur_time.usec;
2021         (void) memmove((char *) &args.file, (char *) &file_ptr->fh2,
2022                         NFS_FHSIZE);
2023         args.attributes.size = (unsigned int) size;
2024
2025         /* make the call */
2026         rpc_stat = clnt_call(NFS_client, NFSPROC_SETATTR,
2027                         xdr_setattr, (char *) &args,
2028                         xdr_setattr, (char *) &reply,
2029                         Nfs_timers[Init]);
2030
2031         if (rpc_stat == RPC_SUCCESS) 
2032                 break;
2033         if (rpc_stat != RPC_TIMEDOUT) {
2034                 (void) fprintf(stderr,
2035                                 "lad_truncate(%ld) RPC call failed : %s\n",
2036                                 size, clnt_sperrno(rpc_stat));
2037         }
2038         if (!LAD_RETRIABLE(rpc_stat)) {
2039                 return(-1);
2040         }
2041     }
2042
2043     if (reply.status != NFS_OK) {
2044         (void) fprintf(stderr, "lad_truncate(%ld) NFS call failed : %s\n",
2045                         size, nfs2_strerror(reply.status));
2046         return(-1);
2047     }
2048     file_ptr->attributes2 = reply.attrstat_u.attributes;
2049     file_ptr->size = fh_size(file_ptr);
2050
2051     return(0);
2052 }
2053
2054 static char *
2055 nfs2_strerror(int status)
2056 {
2057     static char str[40];
2058     switch (status) {
2059         case NFS_OK:
2060             (void) strcpy(str, "no error");
2061             break;
2062         case NFSERR_PERM:
2063             (void) strcpy(str, "Not owner");
2064             break;
2065         case NFSERR_NOENT:
2066             (void) strcpy(str, "No such file or directory");
2067             break;
2068         case NFSERR_IO:
2069             (void) strcpy(str, "I/O error");
2070             break;
2071         case NFSERR_NXIO:
2072             (void) strcpy(str, "No such device or address");
2073             break;
2074         case NFSERR_ACCES:
2075             (void) strcpy(str, "Permission denied");
2076             break;
2077         case NFSERR_EXIST:
2078             (void) strcpy(str, "File exists");
2079             break;
2080         case NFSERR_XDEV:
2081             (void) strcpy(str, "Cross-device link");
2082             break;
2083         case NFSERR_NODEV:
2084             (void) strcpy(str, "No such device");
2085             break;
2086         case NFSERR_NOTDIR:
2087             (void) strcpy(str, "Not a directory");
2088             break;
2089         case NFSERR_ISDIR:
2090             (void) strcpy(str, "Is a directory");
2091             break;
2092         case NFSERR_INVAL:
2093             (void) strcpy(str, "Invalid argument");
2094             break;
2095         case NFSERR_FBIG:
2096             (void) strcpy(str, "File too large");
2097             break;
2098         case NFSERR_NOSPC:
2099             (void) strcpy(str, "No space left on device");
2100             break;
2101         case NFSERR_ROFS:
2102             (void) strcpy(str, "Read-only file system");
2103             break;
2104         case NFSERR_OPNOTSUPP:
2105             (void) strcpy(str, "Operation not supported");
2106             break;
2107         case NFSERR_NAMETOOLONG:
2108             (void) strcpy(str, "File name too long");
2109             break;
2110         case NFSERR_NOTEMPTY:
2111             (void) strcpy(str, "Directory not empty");
2112             break;
2113         case NFSERR_DQUOT:
2114             (void) strcpy(str, "Disc quota exceeded");
2115             break;
2116         case NFSERR_STALE:
2117             (void) strcpy(str, "Stale NFS file handle");
2118             break;
2119         case NFSERR_REMOTE:
2120             (void) strcpy(str, "Object is remote");
2121             break;
2122         case NFSERR_WFLUSH:
2123             (void) strcpy(str, "write cache flushed");
2124             break;
2125         default:
2126             (void) sprintf(str, "Unknown status %d", status);
2127             break;
2128     }
2129     return (str);
2130 }
2131 /* sfs_c_ops.c */