88128136f40a19a3296f686f2486acc52edf13bb
[openafs.git] / src / viced / afsfileprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*  afs_fileprocs.c - Complete File Server request routines              */
11 /*                                                                       */
12 /*  Information Technology Center                                        */
13 /*  Carnegie Mellon University                                           */
14 /*                                                                       */
15 /*  Date: 8/10/88                                                        */
16 /*                                                                       */
17 /*  Function    - A set of routines to handle the various file Server    */
18 /*                  requests; these routines are invoked by rxgen.       */
19 /*                                                                       */
20 /* ********************************************************************** */
21
22 /* 
23  * in Check_PermissionRights, certain privileges are afforded to the owner 
24  * of the volume, or the owner of a file.  Are these considered "use of 
25  * privilege"? 
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30
31 RCSID("$Header$");
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #ifdef  AFS_SGI_ENV
37 #undef SHARED           /* XXX */
38 #endif
39 #ifdef AFS_NT40_ENV
40 #include <fcntl.h>
41 #else
42 #include <sys/param.h>
43 #include <sys/file.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #ifndef AFS_LINUX20_ENV
49 #include <net/if.h>
50 #include <netinet/if_ether.h>
51 #endif
52 #ifdef notdef
53 #include <nlist.h>
54 #endif
55 #endif
56 #ifdef AFS_HPUX_ENV
57 /* included early because of name conflict on IOPEN */
58 #include <sys/inode.h>
59 #ifdef IOPEN
60 #undef IOPEN
61 #endif
62 #endif /* AFS_HPUX_ENV */
63 #include <afs/stds.h>
64 #include <rx/xdr.h>
65 #include <afs/nfs.h>
66 #include <afs/assert.h>
67 #include <lwp.h>
68 #include <lock.h>
69 #include <afs/afsint.h>
70 #include <afs/vldbint.h>
71 #include <afs/errors.h>
72 #include <afs/ihandle.h>
73 #include <afs/vnode.h>
74 #include <afs/volume.h>
75 #include <afs/acl.h>
76 #include <afs/ptclient.h>
77 #include <afs/prs_fs.h>
78 #include <rx/rx.h>
79 #include <rx/rx_globals.h>
80 #include <sys/stat.h>
81 #if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
82 #include <sys/map.h>
83 #endif
84 #if !defined(AFS_NT40_ENV)
85 #include <unistd.h>
86 #endif
87 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
88 #ifdef  AFS_AIX_ENV
89 #include <sys/statfs.h>
90 #include <sys/lockf.h>
91 #else
92 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
93 #include <sys/dk.h>
94 #endif
95 #endif
96 #endif
97 #include <afs/cellconfig.h>
98 #include <afs/keys.h>
99
100 #include <afs/auth.h>
101 #include <signal.h>
102 #include <afs/partition.h>
103 #include "viced.h"
104 #include "host.h"
105 #include <afs/audit.h>
106 #include <afs/afsutil.h>
107
108 #ifdef AFS_PTHREAD_ENV
109 pthread_mutex_t fileproc_glock_mutex;
110 #endif /* AFS_PTHREAD_ENV */
111
112
113 /* Useful local defines used by this module */
114
115 #define DONTCHECK       0
116 #define MustNOTBeDIR    1
117 #define MustBeDIR       2
118
119 #define TVS_SDATA       1
120 #define TVS_SSTATUS     2
121 #define TVS_CFILE       4
122 #define TVS_SLINK       8
123 #define TVS_MKDIR       0x10
124
125 #define CHK_FETCH       0x10
126 #define CHK_FETCHDATA   0x10
127 #define CHK_FETCHACL    0x11
128 #define CHK_FETCHSTATUS 0x12
129 #define CHK_STOREDATA   0x00
130 #define CHK_STOREACL    0x01
131 #define CHK_STORESTATUS 0x02
132
133 #define OWNERREAD       0400
134 #define OWNERWRITE      0200
135 #define OWNEREXEC       0100
136 #ifdef USE_GROUP_PERMS
137 #define GROUPREAD       0040
138 #define GROUPWRITE      0020
139 #define GROUPREXEC      0010
140 #endif
141
142 /* The following errors were not defined in NT. They are given unique
143  * names here to avoid any potential collision.
144  */
145 #define FSERR_ELOOP              90
146 #define FSERR_EOPNOTSUPP        122
147 #define FSERR_ECONNREFUSED      130
148
149 #define NOTACTIVECALL   0
150 #define ACTIVECALL      1
151
152 extern struct afsconf_dir *confDir;
153 extern afs_int32 dataVersionHigh;
154
155 extern  int         SystemId;
156 extern  struct AFSCallStatistics AFSCallStats;
157 struct AFSCallStatistics AFSCallStats;
158 #if FS_STATS_DETAILED
159 struct fs_stats_FullPerfStats afs_FullPerfStats;
160 extern int AnonymousID;
161 #endif /* FS_STATS_DETAILED */
162 #if TRANSARC_VOL_STATS
163 static const char nullString[] = "";
164 #endif /* TRANSARC_VOL_STATS */
165
166 struct afs_FSStats {
167     afs_int32 NothingYet;
168 };
169
170 struct afs_FSStats afs_fsstats;
171
172 void    ResetDebug(), SetDebug(), Terminate();
173 int     CopyOnWrite();          /* returns 0 on success */
174
175
176 void SetSystemStats(), SetAFSStats(), SetVolumeStats();
177 int     LogLevel = 0;
178 int     supported = 1;
179 int     Console = 0;
180 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
181 afs_int32 PctSpare;
182 extern afs_int32 implicitAdminRights;
183
184 static TryLocalVLServer();
185
186 void GetStatus(Vnode *targetptr, AFSFetchStatus *status, afs_int32 rights, afs_int32 anyrights, Vnode *parentptr);
187
188 /*
189  * Externals used by the xstat code.
190  */
191 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
192 extern int CEs, CEBlocks;
193
194 extern int HTs, HTBlocks;
195
196 #ifdef AFS_SGI_XFS_IOPS_ENV
197 #include <afs/xfsattrs.h>
198 static int GetLinkCount(avp, astat)
199      Volume *avp;
200      struct stat *astat;
201 {
202     if (!strcmp("xfs", astat->st_fstype)) {
203         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
204     }
205     else
206         return astat->st_nlink;
207 }
208 #else
209 #define GetLinkCount(V, S) (S)->st_nlink
210 #endif
211
212 afs_int32 SpareComp(avolp)
213     Volume *avolp;
214
215 {
216     register afs_int32 temp;
217
218     FS_LOCK
219     if (PctSpare) {
220         temp = V_maxquota(avolp);
221         if (temp == 0) {
222             /* no matter; doesn't check in this case */
223             FS_UNLOCK
224             return 0;
225         }
226         temp = (temp * PctSpare) / 100;
227         FS_UNLOCK
228         return temp;
229     }
230     else {
231         FS_UNLOCK
232         return BlocksSpare;
233     }
234
235 } /*SpareComp*/
236
237
238 /*
239  * Set the volume synchronization parameter for this volume.  If it changes,
240  * the Cache Manager knows that the volume must be purged from the stat cache.
241  */
242 static SetVolumeSync(async, avol)
243     register struct AFSVolSync *async;
244     register Volume *avol;
245
246 {
247     FS_LOCK
248     /* date volume instance was created */
249     if (async) {
250         if (avol)
251             async->spare1 = avol->header->diskstuff.creationDate;
252         else
253             async->spare1 = 0;
254         async->spare2 = 0;
255         async->spare3 = 0;
256         async->spare4 = 0;
257         async->spare5 = 0;
258         async->spare6 = 0;
259     }
260     FS_UNLOCK
261 } /*SetVolumeSync*/
262
263 /*
264  * Note that this function always returns a held host, so
265  * that CallPostamble can block without the host's disappearing.
266  * Call returns rx connection in passed in *tconn
267  */
268 static CallPreamble(acall, activecall, tconn)
269     register struct rx_call *acall;
270     int activecall;
271     struct rx_connection **tconn;
272
273 {
274     struct host *thost;
275     struct client *tclient;
276     int retry_flag=1;
277     int code = 0;
278     char hoststr[16];
279     if (!tconn) {
280         ViceLog (0, ("CallPreamble: unexpected null tconn!\n"));
281         return -1;
282     }
283     *tconn = rx_ConnectionOf(acall);
284
285     H_LOCK
286 retry:
287     tclient = h_FindClient_r(*tconn);
288     if (tclient->prfail == 1) { /* couldn't get the CPS */
289        if (!retry_flag) {
290           h_ReleaseClient_r(tclient);
291           ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
292           H_UNLOCK
293           return -1001;
294        }
295        retry_flag=0;    /* Retry once */
296
297        /* Take down the old connection and re-read the key file */
298        ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
299        H_UNLOCK
300        code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
301        H_LOCK
302        if (code) {
303           h_ReleaseClient_r(tclient);
304           H_UNLOCK
305           ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
306           return -1001;
307        }
308
309        tclient->prfail = 2;      /* Means re-eval client's cps */
310        h_ReleaseClient_r(tclient);
311        goto retry;
312     }
313
314     thost = tclient->host;
315     tclient->LastCall = thost->LastCall = FT_ApproxTime();
316     if (activecall) /* For all but "GetTime" calls */
317         thost->ActiveCall = thost->LastCall;
318
319     h_Lock_r(thost);
320     if (thost->hostFlags & HOSTDELETED) {
321       ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
322       code = VBUSY; /* raced, so retry */
323     }
324     else if (thost->hostFlags & VENUSDOWN) {
325       if (BreakDelayedCallBacks_r(thost)) {
326         ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP.  Possible network or routing failure.\n",
327                 afs_inet_ntoa_r(thost->host, hoststr)));
328         if ( MultiProbeAlternateAddress_r (thost) ) {
329             ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
330                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
331             code = -1;
332         } else {
333             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
334                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
335             if (BreakDelayedCallBacks_r(thost)) {
336                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
337                         afs_inet_ntoa_r(thost->host, hoststr)));
338                 code = -1;
339             }
340         }
341       }
342     } else {
343        code =  0;
344     }
345
346     h_ReleaseClient_r(tclient);
347     h_Unlock_r(thost);
348     H_UNLOCK
349     return code;      
350
351 } /*CallPreamble*/
352
353
354 static CallPostamble(aconn)
355     register struct rx_connection *aconn;
356
357 {
358     struct host *thost;
359     struct client *tclient;
360
361     H_LOCK
362     tclient = h_FindClient_r(aconn);
363     thost = tclient->host;
364     h_ReleaseClient_r(tclient);
365     h_Release_r(thost);
366     H_UNLOCK
367
368 } /*CallPostamble*/
369
370
371 #define AFSV_BUFFERSIZE 16384 
372
373 static struct afs_buffer {
374     struct afs_buffer *next;
375 } *freeBufferList = 0;
376 static int afs_buffersAlloced = 0;
377
378
379 static FreeSendBuffer(adata)
380     register struct afs_buffer *adata;
381
382 {
383     FS_LOCK
384     afs_buffersAlloced--;
385     adata->next = freeBufferList;
386     freeBufferList = adata;
387     FS_UNLOCK
388     return 0;
389
390 } /*FreeSendBuffer*/
391
392
393 /* allocate space for sender */
394 static char *AllocSendBuffer()
395
396 {
397     register struct afs_buffer *tp;
398
399     FS_LOCK
400     afs_buffersAlloced++;
401     if (!freeBufferList) {
402         FS_UNLOCK
403         return malloc(AFSV_BUFFERSIZE);
404     }
405     tp = freeBufferList;
406     freeBufferList = tp->next;
407     FS_UNLOCK
408     return (char *) tp;
409
410 } /*AllocSendBuffer*/
411
412
413 static int VolumeOwner (client, targetptr)
414     register struct client *client;
415     register Vnode *targetptr;
416
417 {
418     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
419
420     if (owner >= 0)
421         return (client->ViceId == owner);
422     else {
423         /* 
424          * We don't have to check for host's cps since only regular
425          * viceid are volume owners.
426          */
427         return (acl_IsAMember(owner, &client->CPS));
428     }
429
430 } /*VolumeOwner*/
431
432
433 static int VolumeRootVnode (targetptr)
434     Vnode *targetptr;
435
436 {
437     return ((targetptr->vnodeNumber == ROOTVNODE) &&
438             (targetptr->disk.uniquifier == 1));
439
440 } /*VolumeRootVnode*/
441
442
443 SRXAFS_FetchData (acall, Fid, Pos, Len, OutStatus, CallBack, Sync)
444     struct rx_call *acall;              /* Rx call */
445     struct AFSFid *Fid;                 /* Fid of file to fetch */
446     afs_int32 Pos, Len;                 /* Not implemented yet */
447     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
448     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
449     struct AFSVolSync *Sync;            /* synchronization info */
450
451 {
452     int code;
453
454     code = common_FetchData (acall, Fid, Pos, Len, OutStatus,
455                              CallBack, Sync, 0);
456     return code;
457 }
458
459 SRXAFS_FetchData64 (acall, Fid, Pos, Len, OutStatus, CallBack, Sync)
460     struct rx_call *acall;              /* Rx call */
461     struct AFSFid *Fid;                 /* Fid of file to fetch */
462     afs_int64 Pos, Len;                 /* Not implemented yet */
463     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
464     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
465     struct AFSVolSync *Sync;            /* synchronization info */
466 {
467     int code;
468     afs_int32 tPos, tLen;
469
470 #ifdef AFS_64BIT_ENV
471     if (Pos + Len > 0x7fffffff)
472         return E2BIG;
473     tPos = Pos;
474     tLen = Len;
475 #else /* AFS_64BIT_ENV */
476     if (Pos.high || Len.high)
477         return E2BIG;
478     tPos = Pos.low;
479     tLen = Len.low;
480 #endif /* AFS_64BIT_ENV */
481
482     code = common_FetchData (acall, Fid, tPos, tLen, OutStatus,
483                              CallBack, Sync, 1);
484     return code;
485 }
486
487 common_FetchData (acall, Fid, Pos, Len, OutStatus, CallBack, Sync, type)
488     struct rx_call *acall;              /* Rx call */
489     struct AFSFid *Fid;                 /* Fid of file to fetch */
490     afs_int32 Pos, Len;                 /* Not implemented yet */
491     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
492     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
493     struct AFSVolSync *Sync;            /* synchronization info */
494     int type;                           /* 32 bit or 64 bit call */
495
496
497     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
498     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
499     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
500     int     errorCode = 0;                  /* return code to caller */
501     int     fileCode =  0;                  /* return code from vol package */
502     Volume * volptr = 0;                    /* pointer to the volume */
503     struct client *client;                  /* pointer to the client data */
504     struct rx_connection *tcon;             /* the connection we're part of */
505     afs_int32 rights, anyrights;                    /* rights for this and any user */
506     struct client *t_client;                /* tmp ptr to client data */
507     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
508 #if FS_STATS_DETAILED
509     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
510     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
511     struct timeval opStartTime,
512                    opStopTime;              /* Start/stop times for RPC op*/
513     struct timeval xferStartTime,
514                    xferStopTime;            /* Start/stop times for xfer portion*/
515     struct timeval elapsedTime;             /* Transfer time */
516     afs_int32 bytesToXfer;                          /* # bytes to xfer*/
517     afs_int32 bytesXferred;                         /* # bytes actually xferred*/
518     int readIdx;                            /* Index of read stats array to bump*/
519     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
520
521     /*
522      * Set our stats pointers, remember when the RPC operation started, and
523      * tally the operation.
524      */
525     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
526     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
527     FS_LOCK
528     (opP->numOps)++;
529     FS_UNLOCK
530     TM_GetTimeOfDay(&opStartTime, 0);
531 #endif /* FS_STATS_DETAILED */
532
533     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
534             Fid->Volume, Fid->Vnode, Fid->Unique));     
535     FS_LOCK
536     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
537     FS_UNLOCK
538
539     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
540         goto Bad_FetchData;
541
542     /* Get ptr to client data for user Id for logging */
543     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
544     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
545     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
546             Fid->Volume, Fid->Vnode, Fid->Unique,
547             inet_ntoa(logHostAddr), t_client->ViceId)); 
548     /*
549      * Get volume/vnode for the fetched file; caller's access rights to
550      * it are also returned
551      */
552     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
553                                      DONTCHECK, &parentwhentargetnotdir,
554                                      &client, READ_LOCK, &rights, &anyrights))
555         goto Bad_FetchData;
556
557     SetVolumeSync(Sync, volptr);
558
559 #if FS_STATS_DETAILED
560     /*
561      * Remember that another read operation was performed.
562      */
563     FS_LOCK
564     if (client->InSameNetwork)
565         readIdx = VOL_STATS_SAME_NET;
566     else
567         readIdx = VOL_STATS_DIFF_NET;
568     V_stat_reads(volptr, readIdx)++;
569     if (client->ViceId != AnonymousID) {
570         V_stat_reads(volptr, readIdx+1)++;
571     }
572     FS_UNLOCK
573 #endif /* FS_STATS_DETAILED */
574
575     /* Check whether the caller has permission access to fetch the data */
576     if (errorCode = Check_PermissionRights(targetptr, client, rights,
577                                            CHK_FETCHDATA, 0)) 
578         goto Bad_FetchData;
579
580     /*
581      * Drop the read lock on the parent directory after saving the parent
582      * vnode information we need to pass to GetStatus
583      */
584     if (parentwhentargetnotdir != NULL) {
585         tparentwhentargetnotdir = *parentwhentargetnotdir;
586         VPutVnode(&fileCode, parentwhentargetnotdir);
587         assert(!fileCode || (fileCode == VSALVAGE));
588         parentwhentargetnotdir = NULL;
589     }
590
591 #if FS_STATS_DETAILED
592     /*
593      * Remember when the data transfer started.
594      */
595     TM_GetTimeOfDay(&xferStartTime, 0);
596 #endif /* FS_STATS_DETAILED */
597
598     /* actually do the data transfer */
599 #if FS_STATS_DETAILED
600     errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
601                                   &bytesToXfer, &bytesXferred);
602 #else
603     if (errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type))
604         goto Bad_FetchData;
605 #endif /* FS_STATS_DETAILED */
606
607 #if FS_STATS_DETAILED
608     /*
609      * At this point, the data transfer is done, for good or ill.  Remember
610      * when the transfer ended, bump the number of successes/failures, and
611      * integrate the transfer size and elapsed time into the stats.  If the
612      * operation failed, we jump to the appropriate point.
613      */
614     TM_GetTimeOfDay(&xferStopTime, 0);
615     FS_LOCK
616     (xferP->numXfers)++;
617     if (!errorCode) {
618         (xferP->numSuccesses)++;
619
620         /*
621          * Bump the xfer sum by the number of bytes actually sent, NOT the
622          * target number.
623          */
624         tot_bytesXferred += bytesXferred;
625         (xferP->sumBytes) += (tot_bytesXferred >> 10);
626         tot_bytesXferred &= 0x3FF;
627         if (bytesXferred < xferP->minBytes)
628             xferP->minBytes = bytesXferred;
629         if (bytesXferred > xferP->maxBytes)
630             xferP->maxBytes = bytesXferred;
631
632         /*
633          * Tally the size of the object.  Note: we tally the actual size,
634          * NOT the number of bytes that made it out over the wire.
635          */
636         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
637             (xferP->count[0])++;
638         else
639             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
640                 (xferP->count[1])++;
641         else
642             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
643                 (xferP->count[2])++;
644         else
645             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
646                 (xferP->count[3])++;
647         else
648             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
649                 (xferP->count[4])++;
650         else
651             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
652                 (xferP->count[5])++;
653         else
654             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
655                 (xferP->count[6])++;
656         else
657             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
658                 (xferP->count[7])++;
659         else
660             (xferP->count[8])++;
661
662         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
663         fs_stats_AddTo((xferP->sumTime), elapsedTime);
664         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
665         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
666             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
667         }
668         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
669             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
670         }
671       }
672     FS_UNLOCK
673     /*
674      * Finally, go off to tell our caller the bad news in case the
675      * fetch failed.
676      */
677     if (errorCode)
678         goto Bad_FetchData;
679 #endif /* FS_STATS_DETAILED */
680
681     /* write back  the OutStatus from the target vnode  */
682     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
683
684     /* if a r/w volume, promise a callback to the caller */
685     if (VolumeWriteable(volptr))
686         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
687     else {
688       struct AFSFid myFid;              
689       memset(&myFid, 0, sizeof(struct AFSFid));
690       myFid.Volume = Fid->Volume;
691       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
692       }
693
694 Bad_FetchData: 
695     /* Update and store volume/vnode and parent vnodes back */
696     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
697     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
698     CallPostamble(tcon);
699
700 #if FS_STATS_DETAILED
701     TM_GetTimeOfDay(&opStopTime, 0);
702     if (errorCode == 0) {
703         FS_LOCK
704         (opP->numSuccesses)++;
705         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
706         fs_stats_AddTo((opP->sumTime), elapsedTime);
707         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
708         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
709             fs_stats_TimeAssign((opP->minTime), elapsedTime);
710         }
711         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
712             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
713         }
714         FS_UNLOCK
715       }
716
717 #endif /* FS_STATS_DETAILED */
718
719     osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
720     return(errorCode);
721
722 } /*SRXAFS_FetchData*/
723
724
725 SRXAFS_FetchACL (acall, Fid, AccessList, OutStatus, Sync)
726     struct rx_call *acall;              /* Rx call */
727     struct AFSFid *Fid;                 /* Fid of target dir */
728     struct AFSOpaque *AccessList;       /* Returned contents of dir's ACL */
729     struct AFSFetchStatus *OutStatus;   /* Returned status for the dir */
730     struct AFSVolSync *Sync;
731 {
732     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
733     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
734     int     errorCode = 0;              /* return error code to caller */
735     Volume * volptr = 0;                /* pointer to the volume */
736     struct client *client;              /* pointer to the client data */
737     afs_int32 rights, anyrights;                /* rights for this and any user */
738     struct rx_connection *tcon = rx_ConnectionOf(acall);
739     struct client *t_client;                /* tmp ptr to client data */
740     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
741 #if FS_STATS_DETAILED
742     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
743     struct timeval opStartTime,
744                    opStopTime;              /* Start/stop times for RPC op*/
745     struct timeval elapsedTime;             /* Transfer time */
746
747     /*
748      * Set our stats pointer, remember when the RPC operation started, and
749      * tally the operation.
750      */
751     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
752     FS_LOCK
753     (opP->numOps)++;
754     FS_UNLOCK
755     TM_GetTimeOfDay(&opStartTime, 0);
756 #endif /* FS_STATS_DETAILED */
757
758     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
759             Fid->Volume, Fid->Vnode, Fid->Unique));
760     FS_LOCK
761     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
762     FS_UNLOCK
763     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
764         goto Bad_FetchACL;
765
766     /* Get ptr to client data for user Id for logging */
767     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
768     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
769     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
770             Fid->Volume, Fid->Vnode, Fid->Unique,
771             inet_ntoa(logHostAddr), t_client->ViceId));
772
773     AccessList->AFSOpaque_len = 0;
774     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
775
776     /*
777      * Get volume/vnode for the fetched file; caller's access rights to it
778      * are also returned
779      */
780     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
781                                      DONTCHECK, &parentwhentargetnotdir,
782                                      &client, READ_LOCK, &rights, &anyrights))
783         goto Bad_FetchACL;
784
785     SetVolumeSync(Sync, volptr);
786
787     /* Check whether we have permission to fetch the ACL */
788     if (errorCode = Check_PermissionRights(targetptr, client, rights,
789                                            CHK_FETCHACL, 0))
790         goto Bad_FetchACL;
791
792     /* Get the Access List from the dir's vnode */
793     if (errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
794                                        AccessList))
795         goto Bad_FetchACL;
796
797     /* Get OutStatus back From the target Vnode  */
798     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
799
800 Bad_FetchACL: 
801     /* Update and store volume/vnode and parent vnodes back */
802     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
803     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
804             errorCode, AccessList->AFSOpaque_val));
805     CallPostamble(tcon);
806
807 #if FS_STATS_DETAILED
808     TM_GetTimeOfDay(&opStopTime, 0);
809     if (errorCode == 0) {
810         FS_LOCK
811         (opP->numSuccesses)++;
812         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
813         fs_stats_AddTo((opP->sumTime), elapsedTime);
814         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
815         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
816             fs_stats_TimeAssign((opP->minTime), elapsedTime);
817         }
818         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
819             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
820         }
821         FS_UNLOCK
822       }
823
824 #endif /* FS_STATS_DETAILED */
825
826     osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
827     return errorCode;
828
829 } /*SRXAFS_FetchACL*/
830
831
832 /*
833  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
834  * merged into it when possible.
835  */
836 SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync)
837     struct rx_call *acall;
838     struct AFSFid *Fid;                 /* Fid of target file */
839     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
840     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
841     struct AFSVolSync *Sync;            /* volume synchronization parm */
842
843 {
844     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
845     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
846     int     errorCode = 0;              /* return code to caller */
847     Volume * volptr = 0;                /* pointer to the volume */
848     struct client *client;              /* pointer to the client data */
849     afs_int32 rights, anyrights;                /* rights for this and any user */
850     struct client *t_client;            /* tmp ptr to client data */
851     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
852     struct rx_connection *tcon = rx_ConnectionOf(acall);
853
854     /* Get ptr to client data for user Id for logging */
855     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
856     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
857     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
858             Fid->Volume, Fid->Vnode, Fid->Unique,
859             inet_ntoa(logHostAddr), t_client->ViceId));
860     FS_LOCK
861     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
862     FS_UNLOCK
863     /*
864      * Get volume/vnode for the fetched file; caller's rights to it are
865      * also returned
866      */
867     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
868                                      DONTCHECK, &parentwhentargetnotdir,
869                                      &client, READ_LOCK, &rights, &anyrights))
870         goto Bad_FetchStatus;
871
872     /* set volume synchronization information */
873     SetVolumeSync(Sync, volptr);
874
875     /* Are we allowed to fetch Fid's status? */
876     if (targetptr->disk.type != vDirectory) {
877       if (errorCode = Check_PermissionRights(targetptr, client, rights,
878                                              CHK_FETCHSTATUS, 0)) {
879           if (rx_GetCallAbortCode(acall) == errorCode) 
880               rx_SetCallAbortCode(acall, 0);
881           goto Bad_FetchStatus;
882       }
883     }
884
885     /* set OutStatus From the Fid  */
886     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
887
888     /* If a r/w volume, also set the CallBack state */
889     if (VolumeWriteable(volptr))
890         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
891     else {
892       struct AFSFid myFid;              
893       memset(&myFid, 0, sizeof(struct AFSFid));
894       myFid.Volume = Fid->Volume;
895       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
896       }
897
898 Bad_FetchStatus: 
899     /* Update and store volume/vnode and parent vnodes back */
900     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
901     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
902     return errorCode;
903
904 } /*SAFSS_FetchStatus*/
905
906
907 SRXAFS_BulkStatus(acall, Fids, OutStats, CallBacks, Sync)
908     struct rx_call *acall;
909     struct AFSCBFids *Fids;
910     struct AFSBulkStats *OutStats;
911     struct AFSCBs *CallBacks;
912     struct AFSVolSync *Sync;
913
914 {
915     register int i;
916     afs_int32 nfiles;
917     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
918     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
919     int     errorCode = 0;              /* return code to caller */
920     Volume * volptr = 0;                /* pointer to the volume */
921     struct client *client;              /* pointer to the client data */
922     afs_int32 rights, anyrights;                /* rights for this and any user */
923     register struct AFSFid *tfid;       /* file id we're dealing with now */
924     struct rx_connection *tcon = rx_ConnectionOf(acall);
925 #if FS_STATS_DETAILED
926     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
927     struct timeval opStartTime,
928                    opStopTime;              /* Start/stop times for RPC op*/
929     struct timeval elapsedTime;             /* Transfer time */
930
931     /*
932      * Set our stats pointer, remember when the RPC operation started, and
933      * tally the operation.
934      */
935     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
936     FS_LOCK
937     (opP->numOps)++;
938     FS_UNLOCK
939     TM_GetTimeOfDay(&opStartTime, 0);
940 #endif /* FS_STATS_DETAILED */
941
942     ViceLog(1, ("SAFS_BulkStatus\n"));
943     FS_LOCK
944     AFSCallStats.TotalCalls++;
945     FS_UNLOCK
946
947     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
948     if (nfiles <= 0) {                  /* Sanity check */
949         errorCode = EINVAL;
950         goto Audit_and_Return;
951     }
952
953     /* allocate space for return output parameters */
954     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
955         malloc(nfiles * sizeof(struct AFSFetchStatus));
956     OutStats->AFSBulkStats_len = nfiles;
957     CallBacks->AFSCBs_val = (struct AFSCallBack *)
958         malloc(nfiles * sizeof(struct AFSCallBack));
959     CallBacks->AFSCBs_len = nfiles;
960
961     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
962         goto Bad_BulkStatus;
963
964     tfid = Fids->AFSCBFids_val;
965     for (i=0; i<nfiles; i++, tfid++) {
966         /*
967          * Get volume/vnode for the fetched file; caller's rights to it
968          * are also returned
969          */
970         if (errorCode =
971             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
972                              DONTCHECK, &parentwhentargetnotdir, &client,
973                              READ_LOCK, &rights, &anyrights))
974                 goto Bad_BulkStatus;
975         /* set volume synchronization information, but only once per call */
976         if (i == nfiles)
977             SetVolumeSync(Sync, volptr);
978
979         /* Are we allowed to fetch Fid's status? */
980         if (targetptr->disk.type != vDirectory) {
981             if (errorCode = Check_PermissionRights(targetptr, client, rights,
982                                                    CHK_FETCHSTATUS, 0)) {
983                 if (rx_GetCallAbortCode(acall) == errorCode) 
984                     rx_SetCallAbortCode(acall, 0);
985                 goto Bad_BulkStatus;
986             }
987         }
988
989         /* set OutStatus From the Fid  */
990         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
991                   rights, anyrights, parentwhentargetnotdir);
992
993         /* If a r/w volume, also set the CallBack state */
994         if (VolumeWriteable(volptr))
995             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
996                               &CallBacks->AFSCBs_val[i]);
997         else {
998           struct AFSFid myFid;          
999           memset(&myFid, 0, sizeof(struct AFSFid));
1000           myFid.Volume = tfid->Volume;
1001           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
1002                               &CallBacks->AFSCBs_val[i]);
1003         }
1004
1005         /* put back the file ID and volume */
1006         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1007         parentwhentargetnotdir = (Vnode *) 0;
1008         targetptr = (Vnode *) 0;
1009         volptr = (Volume *) 0;
1010     }
1011
1012 Bad_BulkStatus: 
1013     /* Update and store volume/vnode and parent vnodes back */
1014     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1015     CallPostamble(tcon);
1016
1017 #if FS_STATS_DETAILED
1018     TM_GetTimeOfDay(&opStopTime, 0);
1019     if (errorCode == 0) {
1020         FS_LOCK
1021         (opP->numSuccesses)++;
1022         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1023         fs_stats_AddTo((opP->sumTime), elapsedTime);
1024         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1025         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1026             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1027         }
1028         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1029             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1030         }
1031         FS_UNLOCK
1032     }   
1033
1034 #endif /* FS_STATS_DETAILED */
1035
1036 Audit_and_Return:
1037     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
1038     osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
1039     return errorCode;
1040
1041 } /*SRXAFS_BulkStatus*/
1042
1043
1044 SRXAFS_InlineBulkStatus(acall, Fids, OutStats, CallBacks, Sync)
1045     struct rx_call *acall;
1046     struct AFSCBFids *Fids;
1047     struct AFSBulkStats *OutStats;
1048     struct AFSCBs *CallBacks;
1049     struct AFSVolSync *Sync;
1050 {
1051     register int i;
1052     afs_int32 nfiles;
1053     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
1054     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
1055     int     errorCode = 0;              /* return code to caller */
1056     Volume * volptr = 0;                /* pointer to the volume */
1057     struct client *client;              /* pointer to the client data */
1058     afs_int32 rights, anyrights;                /* rights for this and any user */
1059     register struct AFSFid *tfid;       /* file id we're dealing with now */
1060     struct rx_connection *tcon;
1061     AFSFetchStatus *tstatus;
1062 #if FS_STATS_DETAILED
1063     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1064     struct timeval opStartTime,
1065                    opStopTime;              /* Start/stop times for RPC op*/
1066     struct timeval elapsedTime;             /* Transfer time */
1067
1068     /*
1069      * Set our stats pointer, remember when the RPC operation started, and
1070      * tally the operation.
1071      */
1072     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
1073     FS_LOCK
1074     (opP->numOps)++;
1075     FS_UNLOCK
1076     TM_GetTimeOfDay(&opStartTime, 0);
1077 #endif /* FS_STATS_DETAILED */
1078
1079     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
1080     FS_LOCK
1081     AFSCallStats.TotalCalls++;
1082     FS_UNLOCK
1083
1084     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
1085     if (nfiles <= 0) {                  /* Sanity check */
1086         errorCode = EINVAL;
1087         goto Audit_and_Return;
1088     }
1089
1090     /* allocate space for return output parameters */
1091     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
1092         malloc(nfiles * sizeof(struct AFSFetchStatus));
1093     OutStats->AFSBulkStats_len = nfiles;
1094     CallBacks->AFSCBs_val = (struct AFSCallBack *)
1095         malloc(nfiles * sizeof(struct AFSCallBack));
1096     CallBacks->AFSCBs_len = nfiles;
1097
1098     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon)) {
1099         goto Bad_InlineBulkStatus;
1100     }
1101
1102     tfid = Fids->AFSCBFids_val;
1103     for (i=0; i<nfiles; i++, tfid++) {
1104         /*
1105          * Get volume/vnode for the fetched file; caller's rights to it
1106          * are also returned
1107          */
1108         if (errorCode =
1109             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
1110                              DONTCHECK, &parentwhentargetnotdir, &client,
1111                              READ_LOCK, &rights, &anyrights)) {
1112             tstatus = &OutStats->AFSBulkStats_val[i];
1113             tstatus->errorCode = errorCode;
1114             parentwhentargetnotdir = (Vnode *) 0;
1115             targetptr = (Vnode *) 0;
1116             volptr = (Volume *) 0;
1117             continue;
1118         }
1119
1120         /* set volume synchronization information, but only once per call */
1121         if (i == nfiles)
1122             SetVolumeSync(Sync, volptr);
1123
1124         /* Are we allowed to fetch Fid's status? */
1125         if (targetptr->disk.type != vDirectory) {
1126             if (errorCode = Check_PermissionRights(targetptr, client, rights,
1127                                                    CHK_FETCHSTATUS, 0)) {
1128                 tstatus = &OutStats->AFSBulkStats_val[i];
1129                 tstatus->errorCode = errorCode;
1130                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1131                 parentwhentargetnotdir = (Vnode *) 0;
1132                 targetptr = (Vnode *) 0;
1133                 volptr = (Volume *) 0;
1134                 continue;
1135             }
1136         }
1137
1138         /* set OutStatus From the Fid  */
1139         GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], 
1140           rights, anyrights, parentwhentargetnotdir);
1141
1142         /* If a r/w volume, also set the CallBack state */
1143         if (VolumeWriteable(volptr))
1144             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
1145                               &CallBacks->AFSCBs_val[i]);
1146         else {
1147           struct AFSFid myFid;          
1148           memset(&myFid, 0, sizeof(struct AFSFid));
1149           myFid.Volume = tfid->Volume;
1150           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
1151                               &CallBacks->AFSCBs_val[i]);
1152         }
1153
1154         /* put back the file ID and volume */
1155         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1156         parentwhentargetnotdir = (Vnode *) 0;
1157         targetptr = (Vnode *) 0;
1158         volptr = (Volume *) 0;
1159     }
1160
1161 Bad_InlineBulkStatus: 
1162     /* Update and store volume/vnode and parent vnodes back */
1163     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1164     CallPostamble(tcon);
1165
1166 #if FS_STATS_DETAILED
1167     TM_GetTimeOfDay(&opStopTime, 0);
1168     if (errorCode == 0) {
1169         FS_LOCK
1170         (opP->numSuccesses)++;
1171         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1172         fs_stats_AddTo((opP->sumTime), elapsedTime);
1173         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1174         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1175             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1176         }
1177         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1178             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1179         }
1180         FS_UNLOCK
1181     }   
1182
1183 #endif /* FS_STATS_DETAILED */
1184
1185 Audit_and_Return:
1186     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
1187     osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
1188     return 0;
1189
1190 } /*SRXAFS_InlineBulkStatus*/
1191
1192
1193 SRXAFS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync)
1194     struct rx_call *acall;              /* Rx call */
1195     struct AFSFid *Fid;                 /* Fid of target file */
1196     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
1197     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
1198     struct AFSVolSync *Sync;
1199 {
1200     afs_int32 code;
1201     struct rx_connection *tcon;
1202 #if FS_STATS_DETAILED
1203     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1204     struct timeval opStartTime,
1205                    opStopTime;              /* Start/stop times for RPC op*/
1206     struct timeval elapsedTime;             /* Transfer time */
1207
1208     /*
1209      * Set our stats pointer, remember when the RPC operation started, and
1210      * tally the operation.
1211      */
1212     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
1213     FS_LOCK
1214     (opP->numOps)++;
1215     FS_UNLOCK
1216     TM_GetTimeOfDay(&opStartTime, 0);
1217 #endif /* FS_STATS_DETAILED */
1218
1219     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
1220         goto Bad_FetchStatus;
1221
1222     code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
1223
1224 Bad_FetchStatus:    
1225     CallPostamble(tcon);
1226
1227 #if FS_STATS_DETAILED
1228     TM_GetTimeOfDay(&opStopTime, 0);
1229     if (code == 0) {
1230         FS_LOCK
1231         (opP->numSuccesses)++;
1232         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1233         fs_stats_AddTo((opP->sumTime), elapsedTime);
1234         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1235         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1236             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1237         }
1238         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1239             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1240         }
1241         FS_UNLOCK
1242       }
1243
1244 #endif /* FS_STATS_DETAILED */
1245
1246     osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
1247     return code;
1248
1249 } /*SRXAFS_FetchStatus*/
1250
1251
1252 SRXAFS_StoreData (acall, Fid, InStatus, Pos, Length, FileLength, OutStatus, Sync)
1253     struct rx_call *acall;              /* Rx call */
1254     struct AFSFid *Fid;                 /* Fid of taret file */
1255     struct AFSStoreStatus *InStatus;    /* Input Status for Fid */
1256     afs_uint32 Pos;                    /* Not implemented yet */
1257     afs_uint32 Length;                 /* Length of data to store */
1258     afs_uint32 FileLength;             /* Length of file after store */
1259     struct AFSFetchStatus *OutStatus;   /* Returned status for target fid */
1260     struct AFSVolSync *Sync;
1261 {
1262     Vnode * targetptr = 0;              /* pointer to input fid */
1263     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1264     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
1265     int     errorCode = 0;              /* return code for caller */
1266     int     fileCode =  0;              /* return code from vol package */
1267     Volume * volptr = 0;                /* pointer to the volume header */
1268     struct client * client;             /* pointer to client structure */
1269     afs_int32 rights, anyrights;                /* rights for this and any user */
1270     struct client *t_client;            /* tmp ptr to client data */
1271     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1272     struct rx_connection *tcon;
1273 #if FS_STATS_DETAILED
1274     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1275     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
1276     struct timeval opStartTime,
1277                    opStopTime;              /* Start/stop times for RPC op*/
1278     struct timeval xferStartTime,
1279                    xferStopTime;            /* Start/stop times for xfer portion*/
1280     struct timeval elapsedTime;             /* Transfer time */
1281     afs_int32 bytesToXfer;                          /* # bytes to xfer */
1282     afs_int32 bytesXferred;                         /* # bytes actually xfer */
1283     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
1284
1285     /*
1286      * Set our stats pointers, remember when the RPC operation started, and
1287      * tally the operation.
1288      */
1289     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
1290     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
1291     FS_LOCK
1292     (opP->numOps)++;
1293     FS_UNLOCK
1294
1295     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
1296             Fid->Volume, Fid->Vnode, Fid->Unique));
1297     TM_GetTimeOfDay(&opStartTime, 0);
1298 #endif /* FS_STATS_DETAILED */
1299
1300     FS_LOCK
1301     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
1302     FS_UNLOCK
1303
1304     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
1305         goto Bad_StoreData;
1306
1307     /* Get ptr to client data for user Id for logging */
1308     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1309     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1310     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
1311             Fid->Volume, Fid->Vnode, Fid->Unique,
1312             inet_ntoa(logHostAddr), t_client->ViceId));
1313
1314     /*
1315      * Get associated volume/vnode for the stored file; caller's rights
1316      * are also returned
1317      */
1318     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1319                                      MustNOTBeDIR, &parentwhentargetnotdir,
1320                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1321         goto Bad_StoreData;
1322     }
1323
1324     /* set volume synchronization information */
1325     SetVolumeSync(Sync, volptr);
1326
1327     if ((targetptr->disk.type == vSymlink)) {
1328         /* Should we return a better error code here??? */
1329         errorCode = EISDIR;
1330         goto Bad_StoreData;
1331     }
1332
1333     /* Check if we're allowed to store the data */
1334     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1335                                            CHK_STOREDATA, InStatus)) {
1336         goto Bad_StoreData;
1337     }
1338
1339     /*
1340      * Drop the read lock on the parent directory after saving the parent
1341      * vnode information we need to pass to GetStatus
1342      */
1343     if (parentwhentargetnotdir != NULL) {
1344         tparentwhentargetnotdir = *parentwhentargetnotdir;
1345         VPutVnode(&fileCode, parentwhentargetnotdir);
1346         assert(!fileCode || (fileCode == VSALVAGE));
1347         parentwhentargetnotdir = NULL;
1348     }
1349
1350
1351
1352 #if FS_STATS_DETAILED
1353     /*
1354      * Remember when the data transfer started.
1355      */
1356     TM_GetTimeOfDay(&xferStartTime, 0);
1357 #endif /* FS_STATS_DETAILED */
1358
1359     /* Do the actual storing of the data */
1360 #if FS_STATS_DETAILED
1361     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
1362                                   Pos, Length, FileLength,
1363                                   (InStatus->Mask & AFS_FSYNC),
1364                                   &bytesToXfer, &bytesXferred);
1365 #else
1366     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
1367                                       acall, Pos, Length, FileLength,
1368                                       (InStatus->Mask & AFS_FSYNC));
1369     if (errorCode && (!targetptr->changed_newTime))
1370             goto Bad_StoreData;
1371 #endif /* FS_STATS_DETAILED */
1372 #if FS_STATS_DETAILED
1373     /*
1374      * At this point, the data transfer is done, for good or ill.  Remember
1375      * when the transfer ended, bump the number of successes/failures, and
1376      * integrate the transfer size and elapsed time into the stats.  If the
1377      * operation failed, we jump to the appropriate point.
1378      */
1379     TM_GetTimeOfDay(&xferStopTime, 0);
1380     FS_LOCK
1381     (xferP->numXfers)++;
1382     if (!errorCode) {
1383         (xferP->numSuccesses)++;
1384
1385         /*
1386          * Bump the xfer sum by the number of bytes actually sent, NOT the
1387          * target number.
1388          */
1389         tot_bytesXferred += bytesXferred;
1390         (xferP->sumBytes) += (tot_bytesXferred >> 10);
1391         tot_bytesXferred &= 0x3FF;
1392         if (bytesXferred < xferP->minBytes)
1393             xferP->minBytes = bytesXferred;
1394         if (bytesXferred > xferP->maxBytes)
1395             xferP->maxBytes = bytesXferred;
1396       
1397         /*
1398          * Tally the size of the object.  Note: we tally the actual size,
1399          * NOT the number of bytes that made it out over the wire.
1400          */
1401         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
1402             (xferP->count[0])++;
1403         else
1404             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
1405                 (xferP->count[1])++;
1406         else
1407             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
1408                 (xferP->count[2])++;
1409         else
1410             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
1411                 (xferP->count[3])++;
1412         else
1413             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
1414                 (xferP->count[4])++;
1415         else
1416             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
1417                 (xferP->count[5])++;
1418         else
1419             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
1420                 (xferP->count[6])++;
1421         else
1422             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
1423                 (xferP->count[7])++;
1424         else
1425             (xferP->count[8])++;
1426       
1427         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
1428         fs_stats_AddTo((xferP->sumTime), elapsedTime);
1429         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
1430         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
1431             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
1432         }
1433         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
1434             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
1435         }
1436     }
1437     FS_UNLOCK
1438
1439     /*
1440      * Finally, go off to tell our caller the bad news in case the
1441      * store failed.
1442      */
1443     if (errorCode && (!targetptr->changed_newTime))
1444             goto Bad_StoreData;
1445 #endif /* FS_STATS_DETAILED */
1446
1447     /* Update the status of the target's vnode */
1448     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
1449                              volptr, 0);
1450
1451     /* Get the updated File's status back to the caller */
1452     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
1453
1454 Bad_StoreData: 
1455     /* Update and store volume/vnode and parent vnodes back */
1456     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1457     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
1458
1459     CallPostamble(tcon);
1460
1461 #if FS_STATS_DETAILED
1462     TM_GetTimeOfDay(&opStopTime, 0);
1463     if (errorCode == 0) {
1464         FS_LOCK
1465         (opP->numSuccesses)++;
1466         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1467         fs_stats_AddTo((opP->sumTime), elapsedTime);
1468         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1469         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1470             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1471         }
1472         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1473             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1474         }
1475         FS_UNLOCK
1476       }
1477 #endif /* FS_STATS_DETAILED */
1478
1479     osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
1480     return(errorCode);
1481
1482 } /*SRXAFS_StoreData*/
1483
1484 SRXAFS_StoreData64 (acall, Fid, InStatus, Pos, Length, FileLength, OutStatus, Sync)
1485     struct rx_call *acall;              /* Rx call */
1486     struct AFSFid *Fid;                 /* Fid of taret file */
1487     struct AFSStoreStatus *InStatus;    /* Input Status for Fid */
1488     afs_uint64 Pos;                     /* Not implemented yet */
1489     afs_uint64 Length;                  /* Length of data to store */
1490     afs_uint64 FileLength;              /* Length of file after store */
1491     struct AFSFetchStatus *OutStatus;   /* Returned status for target fid */
1492     struct AFSVolSync *Sync;
1493 {
1494     int code;
1495     afs_int32 tPos;
1496     afs_int32 tLength;
1497     afs_int32 tFileLength;
1498
1499 #ifdef AFS_64BIT_ENV
1500     if (FileLength > 0x7fffffff)
1501         return E2BIG;
1502     tPos = Pos;
1503     tLength = Length;
1504     tFileLength = FileLength;
1505 #else /* AFS_64BIT_ENV */
1506     if (FileLength.high)
1507         return E2BIG;
1508     tPos = Pos.low;
1509     tLength = Length.low;
1510     tFileLength = FileLength.low;
1511 #endif /* AFS_64BIT_ENV */
1512
1513     code = SRXAFS_StoreData (acall, Fid, InStatus, tPos, tLength, tFileLength,
1514                              OutStatus, Sync);
1515     return code;
1516 }
1517
1518 SRXAFS_StoreACL (acall, Fid, AccessList, OutStatus, Sync)
1519     struct rx_call *acall;              /* Rx call */
1520     struct AFSFid *Fid;                 /* Target dir's fid */
1521     struct AFSOpaque *AccessList;       /* Access List's contents */
1522     struct AFSFetchStatus *OutStatus;   /* Returned status of fid */
1523     struct AFSVolSync *Sync;
1524 {
1525     Vnode * targetptr = 0;              /* pointer to input fid */
1526     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1527     int     errorCode = 0;              /* return code for caller */
1528     struct AFSStoreStatus InStatus;     /* Input status for fid */
1529     Volume * volptr = 0;                /* pointer to the volume header */
1530     struct client * client;             /* pointer to client structure */
1531     afs_int32 rights, anyrights;                /* rights for this and any user */
1532     struct rx_connection *tcon;
1533     struct client *t_client;            /* tmp ptr to client data */
1534     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1535 #if FS_STATS_DETAILED
1536     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1537     struct timeval opStartTime,
1538                    opStopTime;              /* Start/stop times for RPC op*/
1539     struct timeval elapsedTime;             /* Transfer time */
1540
1541     /*
1542      * Set our stats pointer, remember when the RPC operation started, and
1543      * tally the operation.
1544      */
1545     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
1546     FS_LOCK
1547     (opP->numOps)++;
1548     FS_UNLOCK
1549     TM_GetTimeOfDay(&opStartTime, 0);
1550 #endif /* FS_STATS_DETAILED */
1551     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
1552         goto Bad_StoreACL;
1553
1554     /* Get ptr to client data for user Id for logging */
1555     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1556     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1557     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
1558             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
1559             inet_ntoa(logHostAddr), t_client->ViceId));
1560     FS_LOCK
1561     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
1562     FS_UNLOCK
1563
1564     InStatus.Mask = 0;      /* not storing any status */
1565
1566     /*
1567      * Get associated volume/vnode for the target dir; caller's rights
1568      * are also returned.
1569      */
1570     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1571                                      MustBeDIR, &parentwhentargetnotdir,
1572                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1573         goto Bad_StoreACL;
1574     }
1575
1576     /* set volume synchronization information */
1577     SetVolumeSync(Sync, volptr);
1578
1579     /* Check if we have permission to change the dir's ACL */
1580     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1581                                            CHK_STOREACL, &InStatus)) {
1582         goto Bad_StoreACL;
1583     }
1584
1585     /* Build and store the new Access List for the dir */
1586     if (errorCode = RXStore_AccessList(targetptr, AccessList)) {
1587         goto Bad_StoreACL;
1588     }
1589     
1590     targetptr->changed_newTime = 1; /* status change of directory */
1591
1592     /* convert the write lock to a read lock before breaking callbacks */
1593     VVnodeWriteToRead(&errorCode, targetptr);
1594     assert(!errorCode || errorCode == VSALVAGE);
1595
1596     /* break call backs on the directory  */
1597     BreakCallBack(client->host, Fid, 0);
1598
1599     /* Get the updated dir's status back to the caller */
1600     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
1601
1602 Bad_StoreACL: 
1603     /* Update and store volume/vnode and parent vnodes back */
1604     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1605     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
1606     CallPostamble(tcon);
1607
1608 #if FS_STATS_DETAILED
1609     TM_GetTimeOfDay(&opStopTime, 0);
1610     if (errorCode == 0) {
1611       FS_LOCK
1612       (opP->numSuccesses)++;
1613       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1614       fs_stats_AddTo((opP->sumTime), elapsedTime);
1615       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1616       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1617         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1618       }
1619       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1620         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1621       }
1622       FS_UNLOCK
1623     }
1624 #endif /* FS_STATS_DETAILED */
1625
1626     osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
1627     return errorCode;
1628
1629 } /*SRXAFS_StoreACL*/
1630
1631
1632 /*
1633  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
1634  * should be merged when possible.
1635  */
1636 SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync)
1637     struct rx_call *acall;              /* Rx call */
1638     struct AFSFid *Fid;                 /* Target file's fid */
1639     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1640     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1641     struct AFSVolSync *Sync;
1642
1643 {
1644     Vnode * targetptr = 0;              /* pointer to input fid */
1645     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1646     int     errorCode = 0;              /* return code for caller */
1647     Volume * volptr = 0;                /* pointer to the volume header */
1648     struct client * client;             /* pointer to client structure */
1649     afs_int32 rights, anyrights;                /* rights for this and any user */
1650     struct client *t_client;            /* tmp ptr to client data */
1651     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1652     struct rx_connection *tcon = rx_ConnectionOf(acall);
1653
1654     /* Get ptr to client data for user Id for logging */
1655     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1656     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1657     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
1658             Fid->Volume, Fid->Vnode,    Fid->Unique,
1659             inet_ntoa(logHostAddr), t_client->ViceId));
1660     FS_LOCK
1661     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
1662     FS_UNLOCK
1663     /*
1664      * Get volume/vnode for the target file; caller's rights to it are
1665      * also returned
1666      */
1667     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1668                                      DONTCHECK, &parentwhentargetnotdir,
1669                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1670         goto Bad_StoreStatus;
1671     }
1672
1673     /* set volume synchronization information */
1674     SetVolumeSync(Sync, volptr);
1675
1676     /* Check if the caller has proper permissions to store status to Fid */
1677     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1678                                            CHK_STORESTATUS, InStatus)) {
1679         goto Bad_StoreStatus;
1680     }
1681     /*
1682      * Check for a symbolic link; we can't chmod these (otherwise could
1683      * change a symlink to a mt pt or vice versa)
1684      */
1685     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
1686         errorCode = EINVAL;
1687         goto Bad_StoreStatus;
1688     }
1689
1690     /* Update the status of the target's vnode */
1691     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
1692                              (parentwhentargetnotdir ?
1693                               parentwhentargetnotdir : targetptr), volptr, 0);
1694
1695     /* convert the write lock to a read lock before breaking callbacks */
1696     VVnodeWriteToRead(&errorCode, targetptr);
1697     assert(!errorCode || errorCode == VSALVAGE);
1698
1699     /* Break call backs on Fid */
1700     BreakCallBack(client->host, Fid, 0);
1701
1702     /* Return the updated status back to caller */
1703     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
1704
1705 Bad_StoreStatus: 
1706     /* Update and store volume/vnode and parent vnodes back */
1707     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1708     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
1709     return errorCode;
1710
1711 } /*SAFSS_StoreStatus*/
1712
1713
1714 SRXAFS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync)
1715     struct rx_call *acall;              /* Rx call */
1716     struct AFSFid *Fid;                 /* Target file's fid */
1717     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1718     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1719     struct AFSVolSync *Sync;
1720 {
1721     afs_int32 code;
1722     struct rx_connection *tcon;
1723 #if FS_STATS_DETAILED
1724     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1725     struct timeval opStartTime,
1726                    opStopTime;              /* Start/stop times for RPC op*/
1727     struct timeval elapsedTime;             /* Transfer time */
1728
1729     /*
1730      * Set our stats pointer, remember when the RPC operation started, and
1731      * tally the operation.
1732      */
1733     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
1734     FS_LOCK
1735     (opP->numOps)++;
1736     FS_UNLOCK
1737     TM_GetTimeOfDay(&opStartTime, 0);
1738 #endif /* FS_STATS_DETAILED */
1739
1740     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
1741         goto Bad_StoreStatus;
1742
1743     code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
1744
1745 Bad_StoreStatus:
1746     CallPostamble(tcon);
1747
1748 #if FS_STATS_DETAILED
1749     TM_GetTimeOfDay(&opStopTime, 0);
1750     if (code == 0) {
1751       FS_LOCK
1752       (opP->numSuccesses)++;
1753       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1754       fs_stats_AddTo((opP->sumTime), elapsedTime);
1755       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1756       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1757         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1758       }
1759       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1760         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1761       }
1762       FS_UNLOCK
1763     }
1764
1765 #endif /* FS_STATS_DETAILED */
1766
1767     osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
1768     return code;
1769
1770 } /*SRXAFS_StoreStatus*/
1771
1772
1773 /*
1774  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
1775  * merged in when possible.
1776  */
1777 SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync)
1778     struct rx_call *acall;               /* Rx call */
1779     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1780     char *Name;                          /* File name to remove */
1781     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1782     struct AFSVolSync *Sync;
1783
1784 {
1785     Vnode * parentptr = 0;              /* vnode of input Directory */
1786     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1787     Vnode * targetptr = 0;              /* file to be deleted */
1788     Volume * volptr = 0;                /* pointer to the volume header */
1789     AFSFid fileFid;                     /* area for Fid from the directory */
1790     int     errorCode = 0;              /* error code */
1791     DirHandle dir;                      /* Handle for dir package I/O */
1792     struct client * client;             /* pointer to client structure */
1793     afs_int32 rights, anyrights;                /* rights for this and any user */
1794     struct client *t_client;            /* tmp ptr to client data */
1795     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1796     struct rx_connection *tcon = rx_ConnectionOf(acall);
1797
1798     /* Get ptr to client data for user Id for logging */
1799     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1800     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1801     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1802             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1803             inet_ntoa(logHostAddr), t_client->ViceId));
1804     FS_LOCK
1805     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
1806     FS_UNLOCK
1807     /*
1808      * Get volume/vnode for the parent dir; caller's access rights are
1809      * also returned
1810      */
1811     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1812                                      MustBeDIR, &parentwhentargetnotdir,
1813                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1814         goto Bad_RemoveFile;
1815     }
1816     /* set volume synchronization information */
1817     SetVolumeSync(Sync, volptr);
1818
1819     /* Does the caller has delete (& write) access to the parent directory? */
1820     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
1821         goto Bad_RemoveFile;
1822     }
1823
1824     /* Actually delete the desired file */
1825     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
1826                                  &fileFid, Name, MustNOTBeDIR)) {
1827         goto Bad_RemoveFile;
1828     }
1829
1830     /* Update the vnode status of the parent dir */
1831 #if FS_STATS_DETAILED
1832     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1833                              parentptr->disk.linkCount, client->InSameNetwork);
1834 #else
1835     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1836                              parentptr->disk.linkCount);
1837 #endif /* FS_STATS_DETAILED */
1838
1839     /* Return the updated parent dir's status back to caller */
1840     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
1841
1842     /* Handle internal callback state for the parent and the deleted file */
1843     if (targetptr->disk.linkCount == 0) {
1844         /* no references left, discard entry */
1845         DeleteFileCallBacks(&fileFid);
1846         /* convert the parent lock to a read lock before breaking callbacks */
1847         VVnodeWriteToRead(&errorCode, parentptr);
1848         assert(!errorCode || errorCode == VSALVAGE);
1849     } else {
1850         /* convert the parent lock to a read lock before breaking callbacks */
1851         VVnodeWriteToRead(&errorCode, parentptr);
1852         assert(!errorCode || errorCode == VSALVAGE);
1853         /* convert the target lock to a read lock before breaking callbacks */
1854         VVnodeWriteToRead(&errorCode, targetptr);
1855         assert(!errorCode || errorCode == VSALVAGE);
1856         /* tell all the file has changed */
1857         BreakCallBack(client->host, &fileFid, 1);
1858     }
1859
1860     /* break call back on the directory */
1861     BreakCallBack(client->host, DirFid, 0);
1862
1863 Bad_RemoveFile: 
1864     /* Update and store volume/vnode and parent vnodes back */
1865     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
1866     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
1867     return errorCode;
1868
1869 } /*SAFSS_RemoveFile*/
1870
1871
1872 SRXAFS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync)
1873     struct rx_call *acall;               /* Rx call */
1874     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1875     char *Name;                          /* File name to remove */
1876     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1877     struct AFSVolSync *Sync;
1878 {
1879     afs_int32 code;
1880     struct rx_connection *tcon;
1881 #if FS_STATS_DETAILED
1882     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1883     struct timeval opStartTime,
1884                    opStopTime;              /* Start/stop times for RPC op*/
1885     struct timeval elapsedTime;             /* Transfer time */
1886
1887     /*
1888      * Set our stats pointer, remember when the RPC operation started, and
1889      * tally the operation.
1890      */
1891     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
1892     FS_LOCK
1893     (opP->numOps)++;
1894     FS_UNLOCK
1895     TM_GetTimeOfDay(&opStartTime, 0);
1896 #endif /* FS_STATS_DETAILED */
1897
1898     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
1899         goto Bad_RemoveFile;
1900
1901     code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
1902
1903 Bad_RemoveFile:    
1904     CallPostamble(tcon);
1905
1906 #if FS_STATS_DETAILED
1907     TM_GetTimeOfDay(&opStopTime, 0);
1908     if (code == 0) {
1909       FS_LOCK
1910       (opP->numSuccesses)++;
1911       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1912       fs_stats_AddTo((opP->sumTime), elapsedTime);
1913       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1914       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1915         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1916       }
1917       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1918         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1919       }
1920       FS_UNLOCK
1921     }
1922
1923 #endif /* FS_STATS_DETAILED */
1924
1925     osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
1926     return code;
1927
1928 } /*SRXAFS_RemoveFile*/
1929
1930
1931 /*
1932  * This routine is called exclusively from SRXAFS_CreateFile(), and should
1933  * be merged in when possible.
1934  */
1935 SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid, OutFidStatus,
1936                  OutDirStatus, CallBack, Sync)
1937     struct rx_call *acall;               /* Rx call */
1938     struct AFSFid *DirFid;               /* Parent Dir fid */
1939     char *Name;                          /* File name to be created */
1940     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
1941     struct AFSFid *OutFid;               /* Fid for newly created file */
1942     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
1943     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
1944     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
1945     struct AFSVolSync *Sync;
1946
1947 {
1948     Vnode * parentptr = 0;              /* vnode of input Directory */
1949     Vnode * targetptr = 0;              /* vnode of the new file */
1950     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1951     Volume * volptr = 0;                /* pointer to the volume header */
1952     int     errorCode = 0;              /* error code */
1953     DirHandle dir;                      /* Handle for dir package I/O */
1954     struct client * client;             /* pointer to client structure */
1955     afs_int32 rights, anyrights;                /* rights for this and any user */
1956     struct client *t_client;            /* tmp ptr to client data */
1957     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1958     struct rx_connection *tcon = rx_ConnectionOf(acall);
1959
1960     /* Get ptr to client data for user Id for logging */
1961     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1962     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1963     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1964             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1965             inet_ntoa(logHostAddr), t_client->ViceId));
1966     FS_LOCK
1967     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
1968     FS_UNLOCK
1969     if (!FileNameOK(Name)) {
1970       errorCode = EINVAL;
1971       goto Bad_CreateFile;
1972     }
1973
1974     /*
1975      * Get associated volume/vnode for the parent dir; caller long are
1976      * also returned
1977      */
1978     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1979                                      MustBeDIR, &parentwhentargetnotdir,
1980                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1981         goto Bad_CreateFile;
1982     }
1983
1984     /* set volume synchronization information */
1985     SetVolumeSync(Sync, volptr);
1986
1987     /* Can we write (and insert) onto the parent directory? */
1988     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
1989         goto Bad_CreateFile;
1990     }
1991     /* get a new vnode for the file to be created and set it up */
1992     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
1993                                    Name, OutFid, vFile, nBlocks(0))) {
1994         goto Bad_CreateFile;
1995     }
1996
1997     /* update the status of the parent vnode */
1998 #if FS_STATS_DETAILED
1999     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2000                              parentptr->disk.linkCount, client->InSameNetwork);
2001 #else
2002     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2003                              parentptr->disk.linkCount);
2004 #endif /* FS_STATS_DETAILED */
2005
2006     /* update the status of the new file's vnode */
2007     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
2008                              parentptr, volptr, 0);
2009
2010     /* set up the return status for the parent dir and the newly created file */
2011     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2012     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
2013
2014     /* convert the write lock to a read lock before breaking callbacks */
2015     VVnodeWriteToRead(&errorCode, parentptr);
2016     assert(!errorCode || errorCode == VSALVAGE);
2017     
2018     /* break call back on parent dir */
2019     BreakCallBack(client->host, DirFid, 0);
2020
2021     /* Return a callback promise for the newly created file to the caller */
2022     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
2023
2024 Bad_CreateFile:
2025     /* Update and store volume/vnode and parent vnodes back */
2026     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2027     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
2028     return errorCode;
2029
2030 } /*SAFSS_CreateFile*/
2031
2032
2033 SRXAFS_CreateFile (acall, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
2034     struct rx_call *acall;               /* Rx call */
2035     struct AFSFid *DirFid;               /* Parent Dir fid */
2036     char *Name;                          /* File name to be created */
2037     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
2038     struct AFSFid *OutFid;               /* Fid for newly created file */
2039     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
2040     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
2041     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
2042     struct AFSVolSync *Sync;
2043 {
2044     afs_int32 code;
2045     struct rx_connection *tcon;
2046 #if FS_STATS_DETAILED
2047     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2048     struct timeval opStartTime,
2049                    opStopTime;              /* Start/stop times for RPC op*/
2050     struct timeval elapsedTime;             /* Transfer time */
2051
2052     /*
2053      * Set our stats pointer, remember when the RPC operation started, and
2054      * tally the operation.
2055      */
2056     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
2057     FS_LOCK
2058     (opP->numOps)++;
2059     FS_UNLOCK
2060     TM_GetTimeOfDay(&opStartTime, 0);
2061 #endif /* FS_STATS_DETAILED */
2062
2063     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
2064         goto Bad_CreateFile;
2065
2066     code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
2067                             OutFidStatus, OutDirStatus, CallBack, Sync);
2068
2069 Bad_CreateFile:    
2070     CallPostamble(tcon);
2071
2072 #if FS_STATS_DETAILED
2073     TM_GetTimeOfDay(&opStopTime, 0);
2074     if (code == 0) {
2075       FS_LOCK
2076       (opP->numSuccesses)++;
2077       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2078       fs_stats_AddTo((opP->sumTime), elapsedTime);
2079       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2080       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2081         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2082       }
2083       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2084         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2085       }
2086       FS_UNLOCK
2087     }
2088 #endif /* FS_STATS_DETAILED */
2089
2090     osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2091     return code;
2092
2093 } /*SRXAFS_CreateFile*/
2094
2095
2096 /*
2097  * This routine is called exclusively from SRXAFS_Rename(), and should be
2098  * merged in when possible.
2099  */
2100 SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus,
2101              OutNewDirStatus, Sync)
2102     struct rx_call *acall;                  /* Rx call */
2103     struct AFSFid *OldDirFid;               /* From parent dir's fid */
2104     char *OldName;                          /* From file name */
2105     struct AFSFid *NewDirFid;               /* To parent dir's fid */
2106     char *NewName;                          /* To new file name */
2107     struct AFSFetchStatus *OutOldDirStatus; /* Output status for From parent dir */
2108     struct AFSFetchStatus *OutNewDirStatus; /* Output status for To parent dir */
2109     struct AFSVolSync *Sync;
2110
2111 {
2112     Vnode * oldvptr = 0;        /* vnode of the old Directory */
2113     Vnode * newvptr = 0;        /* vnode of the new Directory */
2114     Vnode * fileptr = 0;        /* vnode of the file to move */
2115     Vnode * newfileptr = 0;     /* vnode of the file to delete */
2116     Vnode * testvptr = 0;       /* used in directory tree walk */
2117     Vnode * parent = 0;         /* parent for use in SetAccessList */
2118     int     errorCode = 0;      /* error code */
2119     int     fileCode = 0;       /* used when writing Vnodes */
2120     VnodeId testnode;           /* used in directory tree walk */
2121     AFSFid fileFid;             /* Fid of file to move */
2122     AFSFid newFileFid;          /* Fid of new file */
2123     DirHandle olddir;           /* Handle for dir package I/O */
2124     DirHandle newdir;           /* Handle for dir package I/O */
2125     DirHandle filedir;          /* Handle for dir package I/O */
2126     DirHandle newfiledir;       /* Handle for dir package I/O */
2127     Volume * volptr = 0;        /* pointer to the volume header */
2128     struct client * client;     /* pointer to client structure */
2129     afs_int32 rights, anyrights;        /* rights for this and any user */
2130     afs_int32 newrights;                /* rights for this user */
2131     afs_int32 newanyrights;             /* rights for any user */
2132     int doDelete;               /* deleted the rename target (ref count now 0) */
2133     int code;
2134     struct client *t_client;            /* tmp ptr to client data */
2135     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2136     struct rx_connection *tcon = rx_ConnectionOf(acall);
2137
2138     /* Get ptr to client data for user Id for logging */
2139     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2140     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2141     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
2142             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
2143             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
2144             NewDirFid->Unique,
2145             inet_ntoa(logHostAddr), t_client->ViceId));
2146     FS_LOCK
2147     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
2148     FS_UNLOCK
2149     if (!FileNameOK(NewName)) {
2150         errorCode = EINVAL;
2151         goto Bad_Rename;
2152     }
2153     if (OldDirFid->Volume != NewDirFid->Volume) {
2154         DFlush();
2155         errorCode = EXDEV;
2156         goto Bad_Rename;
2157     }
2158     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
2159          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
2160          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
2161         DFlush();
2162         errorCode = EINVAL;
2163         goto Bad_Rename;
2164     }
2165
2166     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
2167         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
2168                                           &oldvptr, MustBeDIR, &parent,
2169                                           &client, WRITE_LOCK, &rights,
2170                                           &anyrights)) {
2171             DFlush();
2172             goto Bad_Rename;
2173         }
2174         if (OldDirFid->Vnode == NewDirFid->Vnode) {
2175             newvptr = oldvptr;
2176             newrights = rights, newanyrights = anyrights;
2177         }
2178         else
2179             if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2180                                              &newvptr, MustBeDIR, &parent,
2181                                              &client, WRITE_LOCK, &newrights,
2182                                              &newanyrights)) {
2183                 DFlush();
2184                 goto Bad_Rename;
2185             }
2186     }
2187     else {
2188         if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2189                                          &newvptr, MustBeDIR, &parent,
2190                                          &client, WRITE_LOCK, &newrights,
2191                                          &newanyrights)) {
2192             DFlush();
2193             goto Bad_Rename;
2194         }
2195         if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
2196                                          MustBeDIR, &parent, &client, WRITE_LOCK,
2197                                          &rights, &anyrights)) {
2198             DFlush();
2199             goto Bad_Rename;
2200         }
2201     }
2202
2203     /* set volume synchronization information */
2204     SetVolumeSync(Sync, volptr);
2205
2206     if (errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE)) {
2207         goto Bad_Rename;
2208     }
2209     if (errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT)) {
2210         goto Bad_Rename;
2211     }
2212
2213     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
2214     *  call to CopyOnWrite returns error, it is not necessary to revert back
2215     *  the effects of the first call because the contents of the volume is 
2216     *  not modified, it is only replicated.
2217     */
2218     if (oldvptr->disk.cloned)
2219     {
2220         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
2221          if ( errorCode = CopyOnWrite(oldvptr, volptr) )
2222                 goto Bad_Rename;
2223     }
2224     SetDirHandle(&olddir, oldvptr);
2225     if (newvptr->disk.cloned)
2226     {
2227         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
2228         if ( errorCode = CopyOnWrite(newvptr, volptr) )
2229                 goto Bad_Rename;        
2230     }
2231
2232     SetDirHandle(&newdir, newvptr);
2233
2234     /* Lookup the file to delete its vnode */
2235     if (Lookup(&olddir, OldName, &fileFid)) {
2236         errorCode = ENOENT;
2237         goto Bad_Rename;
2238     }
2239     if (fileFid.Vnode == oldvptr->vnodeNumber ||
2240         fileFid.Vnode == newvptr->vnodeNumber) {
2241         errorCode = FSERR_ELOOP;
2242         goto Bad_Rename;
2243     }
2244     fileFid.Volume = V_id(volptr);
2245     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
2246     if (errorCode != 0) {
2247         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
2248         VTakeOffline (volptr);
2249         goto Bad_Rename;
2250     }
2251     if (fileptr->disk.uniquifier != fileFid.Unique) {
2252         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
2253         VTakeOffline (volptr);
2254         errorCode = EIO;
2255         goto Bad_Rename;
2256     }
2257
2258     if (fileptr->disk.type != vDirectory &&
2259         oldvptr != newvptr &&
2260         fileptr->disk.linkCount != 1) {
2261         /*
2262          * Hard links exist to this file - cannot move one of the links to
2263          * a new directory because of AFS restrictions (this is the same
2264          * reason that links cannot be made across directories, i.e.
2265          * access lists)
2266          */
2267         errorCode = EXDEV;
2268         goto Bad_Rename;
2269     }
2270
2271     /* Lookup the new file  */
2272     if (!(Lookup(&newdir, NewName, &newFileFid))) {
2273         if (!(newrights & PRSFS_DELETE)) {
2274             errorCode = EACCES;
2275             goto Bad_Rename;
2276         }
2277         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
2278                 newFileFid.Vnode == newvptr->vnodeNumber ||
2279                 newFileFid.Vnode == fileFid.Vnode) {
2280             errorCode = EINVAL;
2281             goto Bad_Rename;
2282         }
2283         newFileFid.Volume = V_id(volptr);
2284         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
2285         if (errorCode != 0) {
2286             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
2287             VTakeOffline (volptr);
2288             goto Bad_Rename;
2289         }
2290         if (fileptr->disk.uniquifier != fileFid.Unique) {
2291             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
2292             VTakeOffline (volptr);
2293             errorCode = EIO;
2294             goto Bad_Rename;
2295         }
2296         SetDirHandle(&newfiledir, newfileptr);
2297         /* Now check that we're moving directories over directories properly, etc.
2298          * return proper POSIX error codes:
2299          * if fileptr is a file and new is a dir: EISDIR.
2300          * if fileptr is a dir and new is a file: ENOTDIR.
2301          * Also, dir to be removed must be empty, of course.
2302          */
2303         if (newfileptr->disk.type == vDirectory) {
2304             if (fileptr->disk.type != vDirectory) {
2305                 errorCode = EISDIR;
2306                 goto Bad_Rename;
2307             }
2308             if ((IsEmpty(&newfiledir))) {
2309                 errorCode = EEXIST;
2310                 goto Bad_Rename;
2311             }
2312         }
2313         else {
2314             if (fileptr->disk.type == vDirectory) {
2315                 errorCode = ENOTDIR;
2316                 goto Bad_Rename;
2317             }
2318         }
2319     }
2320
2321     /*
2322      * ok - now we check that the old name is not above new name in the
2323      * directory structure.  This is to prevent removing a subtree alltogether
2324      */
2325     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
2326         for (testnode = newvptr->disk.parent; testnode != 0;) {
2327             if (testnode == oldvptr->vnodeNumber) {
2328                 testnode = oldvptr->disk.parent;
2329                 continue;
2330             }
2331             if ((testnode == fileptr->vnodeNumber) ||
2332                 (testnode == newvptr->vnodeNumber)) {
2333                 errorCode = FSERR_ELOOP;
2334                 goto Bad_Rename;
2335             }
2336             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
2337                 errorCode = FSERR_ELOOP;
2338                 goto Bad_Rename;
2339             }
2340             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
2341             assert(errorCode == 0);
2342             testnode = testvptr->disk.parent;
2343             VPutVnode(&errorCode, testvptr);
2344             assert(errorCode == 0);
2345         }
2346     }
2347     /* Do the CopyonWrite first before modifying anything else. Copying is
2348      *  required because we may have to change entries for .. 
2349      */
2350     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
2351     {
2352         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
2353         if ( errorCode = CopyOnWrite(fileptr, volptr) )
2354                 goto Bad_Rename;
2355     }
2356
2357     /* If the new name exists already, delete it and the file it points to */
2358     doDelete = 0;
2359     if (newfileptr) {
2360         /* Delete NewName from its directory */
2361         code = Delete(&newdir, NewName);
2362         assert(code == 0);
2363
2364         /* Drop the link count */
2365         newfileptr->disk.linkCount--;
2366         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
2367             VAdjustDiskUsage(&errorCode, volptr,
2368                              -(int)nBlocks(newfileptr->disk.length), 0);
2369             if (VN_GET_INO(newfileptr)) {
2370                 IH_REALLYCLOSE(newfileptr->handle);
2371                 errorCode = IH_DEC(V_linkHandle(volptr),
2372                                  VN_GET_INO(newfileptr),
2373                                  V_parentId(volptr));
2374                 IH_RELEASE(newfileptr->handle);
2375                 if (errorCode == -1) {
2376                     ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
2377                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
2378                                 NewName, errno));
2379                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
2380                         ViceLog(0, ("Do we need to fsck?"));
2381                 } 
2382             }
2383             VN_SET_INO(newfileptr, (Inode)0);
2384             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
2385             doDelete = 1;
2386         } else {
2387             /* Link count did not drop to zero.
2388              * Mark NewName vnode as changed - updates stime.
2389              */
2390             newfileptr->changed_newTime = 1;
2391         }
2392     }
2393     
2394     /*
2395      * If the create below fails, and the delete above worked, we have
2396      * removed the new name and not replaced it.  This is not very likely,
2397      * but possible.  We could try to put the old file back, but it is
2398      * highly unlikely that it would work since it would involve issuing
2399      * another create.
2400      */
2401     if (errorCode = Create(&newdir,(char *) NewName, &fileFid))
2402         goto Bad_Rename;
2403
2404     /* Delete the old name */
2405     assert(Delete(&olddir,(char *) OldName) == 0);
2406
2407     /* if the directory length changes, reflect it in the statistics */
2408 #if FS_STATS_DETAILED
2409     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2410                              oldvptr->disk.linkCount, client->InSameNetwork);
2411     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2412                              newvptr->disk.linkCount, client->InSameNetwork);
2413 #else
2414     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2415                              oldvptr->disk.linkCount);
2416     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2417                              newvptr->disk.linkCount);
2418 #endif /* FS_STATS_DETAILED */
2419
2420     if (oldvptr == newvptr)
2421         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
2422
2423     fileptr->disk.parent = newvptr->vnodeNumber;
2424     fileptr->changed_newTime = 1;       /* status change of moved file */
2425
2426     /* if we are dealing with a rename of a directory */
2427     if (fileptr->disk.type == vDirectory) {
2428         assert(!fileptr->disk.cloned);          
2429         SetDirHandle(&filedir, fileptr);
2430         /* fix .. to point to the correct place */
2431         Delete(&filedir, ".."); /* No assert--some directories may be bad */
2432         assert(Create(&filedir, "..", NewDirFid) == 0);
2433         fileptr->disk.dataVersion++;
2434         /* if the parent directories are different the link counts have to be   */
2435         /* changed due to .. in the renamed directory */
2436         if (oldvptr != newvptr) {
2437             oldvptr->disk.linkCount--;
2438             newvptr->disk.linkCount++;
2439         }
2440     }
2441
2442     /* set up return status */
2443     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
2444     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
2445     if (newfileptr && doDelete) {
2446         DeleteFileCallBacks(&newFileFid);       /* no other references */
2447     }
2448
2449     DFlush();
2450
2451     /* convert the write locks to a read locks before breaking callbacks */
2452     VVnodeWriteToRead(&errorCode, newvptr);
2453     assert(!errorCode || errorCode == VSALVAGE);
2454     if (oldvptr != newvptr) {
2455         VVnodeWriteToRead(&errorCode, oldvptr);
2456         assert(!errorCode || errorCode == VSALVAGE);
2457     }
2458     if (newfileptr && !doDelete) {
2459         /* convert the write lock to a read lock before breaking callbacks */
2460         VVnodeWriteToRead(&errorCode, newfileptr);
2461         assert(!errorCode || errorCode == VSALVAGE);
2462     }
2463
2464     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
2465     BreakCallBack(client->host, NewDirFid, 0);
2466     if (oldvptr != newvptr) {
2467         BreakCallBack(client->host, OldDirFid, 0);
2468         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
2469             BreakCallBack(client->host, &fileFid, 0);
2470     }
2471     if (newfileptr) {
2472         /* Note:  it is not necessary to break the callback */
2473         if (doDelete)
2474             DeleteFileCallBacks(&newFileFid);   /* no other references */
2475         else
2476             /* other's still exist (with wrong link count) */
2477             BreakCallBack(client->host, &newFileFid, 1);
2478     }
2479
2480 Bad_Rename: 
2481     if (newfileptr) {
2482         VPutVnode(&fileCode, newfileptr);
2483         assert(fileCode == 0);
2484     }
2485     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
2486                      oldvptr, volptr);
2487     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
2488     return errorCode;
2489
2490 } /*SAFSS_Rename*/
2491
2492
2493 SRXAFS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus, OutNewDirStatus, Sync)
2494     struct rx_call *acall;                   /* Rx call */
2495     struct AFSFid *OldDirFid;                /* From parent dir's fid */
2496     char *OldName;                           /* From file name */
2497     struct AFSFid *NewDirFid;                /* To parent dir's fid */
2498     char *NewName;                           /* To new file name */
2499     struct AFSFetchStatus *OutOldDirStatus;  /* Output status for From parent dir */
2500     struct AFSFetchStatus *OutNewDirStatus;  /* Output status for To parent dir */
2501     struct AFSVolSync *Sync;
2502 {
2503     afs_int32 code;
2504     struct rx_connection *tcon;
2505 #if FS_STATS_DETAILED
2506     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2507     struct timeval opStartTime,
2508                    opStopTime;              /* Start/stop times for RPC op*/
2509     struct timeval elapsedTime;             /* Transfer time */
2510
2511     /*
2512      * Set our stats pointer, remember when the RPC operation started, and
2513      * tally the operation.
2514      */
2515     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
2516     FS_LOCK
2517     (opP->numOps)++;
2518     FS_UNLOCK
2519     TM_GetTimeOfDay(&opStartTime, 0);
2520 #endif /* FS_STATS_DETAILED */
2521
2522     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
2523         goto Bad_Rename;
2524
2525     code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
2526                          OutOldDirStatus, OutNewDirStatus, Sync);
2527
2528 Bad_Rename:    
2529     CallPostamble(tcon);
2530
2531 #if FS_STATS_DETAILED
2532     TM_GetTimeOfDay(&opStopTime, 0);
2533     if (code == 0) {
2534       FS_LOCK
2535       (opP->numSuccesses)++;
2536       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2537       fs_stats_AddTo((opP->sumTime), elapsedTime);
2538       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2539       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2540         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2541       }
2542       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2543         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2544       }
2545       FS_UNLOCK
2546     }
2547
2548 #endif /* FS_STATS_DETAILED */
2549
2550     osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
2551     return code;
2552
2553 } /*SRXAFS_Rename*/
2554
2555
2556 /*
2557  * This routine is called exclusively by SRXAFS_Symlink(), and should be
2558  * merged into it when possible.
2559  */
2560 SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2561     struct rx_call *acall;               /* Rx call */
2562     struct AFSFid *DirFid;               /* Parent dir's fid */
2563     char *Name;                          /* File name to create */
2564     char *LinkContents;                  /* Contents of the new created file */
2565     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2566     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2567     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2568     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2569     struct AFSVolSync *Sync;             /* volume synchronization information */
2570
2571 {
2572     Vnode * parentptr = 0;              /* vnode of input Directory */
2573     Vnode * targetptr = 0;              /* vnode of the new link */
2574     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2575     int     errorCode = 0;              /* error code */
2576     int code = 0;
2577     DirHandle dir;                      /* Handle for dir package I/O */
2578     Volume * volptr = 0;                /* pointer to the volume header */
2579     struct client * client;             /* pointer to client structure */
2580     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
2581     struct client *t_client;            /* tmp ptr to client data */
2582     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2583     FdHandle_t *fdP;
2584     struct rx_connection *tcon = rx_ConnectionOf(acall);
2585
2586     /* Get ptr to client data for user Id for logging */
2587     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2588     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2589     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
2590             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2591             inet_ntoa(logHostAddr), t_client->ViceId));
2592     FS_LOCK
2593     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
2594     FS_UNLOCK
2595     if (!FileNameOK(Name)) {
2596         errorCode = EINVAL;
2597         goto Bad_SymLink;
2598     }
2599
2600     /*
2601      * Get the vnode and volume for the parent dir along with the caller's
2602      * rights to it
2603      */
2604     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2605                                      MustBeDIR, &parentwhentargetnotdir,
2606                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2607         goto Bad_SymLink;
2608     }
2609
2610     /* set volume synchronization information */
2611     SetVolumeSync(Sync, volptr);
2612
2613     /* Does the caller has insert (and write) access to the parent directory? */
2614     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2615         goto Bad_SymLink;
2616     }
2617
2618     /*
2619      * If we're creating a mount point (any x bits clear), we must have
2620      * administer access to the directory, too.  Always allow sysadmins
2621      * to do this.
2622      */
2623     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
2624         /*
2625          * We have a mountpoint, 'cause we're trying to set the Unix mode
2626          * bits to something with some x bits missing (default mode bits
2627          * if AFS_SETMODE is false is 0777)
2628          */
2629         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
2630             errorCode = EACCES;
2631             goto Bad_SymLink;
2632         }
2633     }
2634  
2635     /* get a new vnode for the symlink and set it up */
2636     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
2637                                    Name, OutFid, vSymlink,
2638                                    nBlocks(strlen((char *) LinkContents)))) {
2639         goto Bad_SymLink;
2640     }
2641
2642     /* update the status of the parent vnode */
2643 #if FS_STATS_DETAILED
2644     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2645                              parentptr->disk.linkCount, client->InSameNetwork);
2646 #else
2647     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2648                              parentptr->disk.linkCount);
2649 #endif /* FS_STATS_DETAILED */
2650
2651     /* update the status of the new symbolic link file vnode */
2652     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
2653                              volptr, strlen((char *)LinkContents));
2654
2655     /* Write the contents of the symbolic link name into the target inode */
2656     fdP = IH_OPEN(targetptr->handle);
2657     assert(fdP != NULL);
2658     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
2659     FDH_CLOSE(fdP);
2660     /*
2661      * Set up and return modified status for the parent dir and new symlink
2662      * to caller.
2663      */
2664     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2665     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
2666
2667     /* convert the write lock to a read lock before breaking callbacks */
2668     VVnodeWriteToRead(&errorCode, parentptr);
2669     assert(!errorCode || errorCode == VSALVAGE);
2670
2671     /* break call back on the parent dir */
2672     BreakCallBack(client->host, DirFid, 0);
2673
2674 Bad_SymLink: 
2675     /* Write the all modified vnodes (parent, new files) and volume back */
2676     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2677     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
2678     return errorCode;
2679
2680 } /*SAFSS_Symlink*/
2681
2682
2683 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2684     struct AFSVolSync *Sync;
2685     struct rx_call *acall;               /* Rx call */
2686     struct AFSFid *DirFid;               /* Parent dir's fid */
2687     char *Name;                          /* File name to create */
2688     char *LinkContents;                  /* Contents of the new created file */
2689     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2690     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2691     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2692     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2693
2694 {
2695     afs_int32 code;
2696     struct rx_connection *tcon;
2697 #if FS_STATS_DETAILED
2698     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2699     struct timeval opStartTime,
2700                    opStopTime;              /* Start/stop times for RPC op*/
2701     struct timeval elapsedTime;             /* Transfer time */
2702
2703     /*
2704      * Set our stats pointer, remember when the RPC operation started, and
2705      * tally the operation.
2706      */
2707     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
2708     FS_LOCK
2709     (opP->numOps)++;
2710     FS_UNLOCK
2711     TM_GetTimeOfDay(&opStartTime, 0);
2712 #endif /* FS_STATS_DETAILED */
2713
2714     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
2715         goto Bad_Symlink;
2716
2717     code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
2718                          OutFidStatus, OutDirStatus, Sync);
2719
2720 Bad_Symlink:    
2721     CallPostamble(tcon);
2722
2723 #if FS_STATS_DETAILED
2724     TM_GetTimeOfDay(&opStopTime, 0);
2725     if (code == 0) {
2726       FS_LOCK
2727       (opP->numSuccesses)++;
2728       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2729       fs_stats_AddTo((opP->sumTime), elapsedTime);
2730       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2731       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2732         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2733       }
2734       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2735         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2736       }
2737       FS_UNLOCK
2738     }
2739
2740 #endif /* FS_STATS_DETAILED */
2741
2742     osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2743     return code;
2744
2745 } /*SRXAFS_Symlink*/
2746
2747
2748 /*
2749  * This routine is called exclusively by SRXAFS_Link(), and should be
2750  * merged into it when possible.
2751  */
2752 SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2753     struct rx_call *acall;               /* Rx call */
2754     struct AFSFid *DirFid;               /* Parent dir's fid */
2755     char *Name;                          /* File name to create */
2756     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2757     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2758     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2759     struct AFSVolSync *Sync;
2760
2761 {
2762     Vnode * parentptr = 0;              /* vnode of input Directory */
2763     Vnode * targetptr = 0;              /* vnode of the new file */
2764     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2765     Volume * volptr = 0;                /* pointer to the volume header */
2766     int     errorCode = 0;              /* error code */
2767     DirHandle dir;                      /* Handle for dir package I/O */
2768     struct client * client;             /* pointer to client structure */
2769     afs_int32 rights, anyrights;                /* rights for this and any user */
2770     struct client *t_client;            /* tmp ptr to client data */
2771     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2772     struct rx_connection *tcon = rx_ConnectionOf(acall);
2773
2774     /* Get ptr to client data for user Id for logging */
2775     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2776     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2777     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
2778             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2779             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
2780             inet_ntoa(logHostAddr), t_client->ViceId));
2781     FS_LOCK
2782     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
2783     FS_UNLOCK
2784     if (DirFid->Volume != ExistingFid->Volume) {
2785         errorCode = EXDEV;
2786         goto Bad_Link;
2787     }
2788     if (!FileNameOK(Name)) {
2789         errorCode = EINVAL;
2790         goto Bad_Link;
2791     }
2792
2793     /*
2794      * Get the vnode and volume for the parent dir along with the caller's
2795      * rights to it
2796      */
2797     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2798                                      MustBeDIR, &parentwhentargetnotdir,
2799                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2800         goto Bad_Link;
2801     }
2802
2803     /* set volume synchronization information */
2804     SetVolumeSync(Sync, volptr);
2805
2806     /* Can the caller insert into the parent directory? */
2807     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2808         goto Bad_Link;
2809     }
2810
2811     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
2812         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
2813       /* AFS fileservers always have directory vnodes that are odd.   */
2814       errorCode = EISDIR;
2815       goto Bad_Link;
2816     }
2817
2818     /* get the file vnode  */
2819     if (errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK)) {
2820         goto Bad_Link;
2821     }
2822     if (targetptr->disk.type != vFile) {
2823         errorCode = EISDIR;
2824         goto Bad_Link;
2825     }
2826     if (targetptr->disk.parent != DirFid->Vnode) {
2827         errorCode = EXDEV;
2828         goto Bad_Link;
2829     }
2830     if (parentptr->disk.cloned) 
2831     {
2832         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
2833         if ( errorCode = CopyOnWrite(parentptr, volptr))
2834                 goto Bad_Link;          /* disk full error */
2835     }
2836
2837     /* add the name to the directory */
2838     SetDirHandle(&dir, parentptr);
2839     if (errorCode = Create(&dir, (char *)Name, ExistingFid))
2840         goto Bad_Link;
2841     DFlush();
2842
2843     /* update the status in the parent vnode */
2844     /**WARNING** --> disk.author SHOULDN'T be modified???? */
2845 #if FS_STATS_DETAILED
2846     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2847                              parentptr->disk.linkCount, client->InSameNetwork);
2848 #else
2849     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2850                              parentptr->disk.linkCount);
2851 #endif /* FS_STATS_DETAILED */
2852
2853     targetptr->disk.linkCount++;
2854     targetptr->disk.author = client->ViceId;
2855     targetptr->changed_newTime = 1; /* Status change of linked-to file */
2856
2857     /* set up return status */
2858     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2859     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
2860
2861     /* convert the write locks to read locks before breaking callbacks */
2862     VVnodeWriteToRead(&errorCode, targetptr);
2863     assert(!errorCode || errorCode == VSALVAGE);
2864     VVnodeWriteToRead(&errorCode, parentptr);
2865     assert(!errorCode || errorCode == VSALVAGE);
2866     
2867     /* break call back on DirFid */
2868     BreakCallBack(client->host, DirFid, 0);
2869     /*
2870      * We also need to break the callback for the file that is hard-linked since part 
2871      * of its status (like linkcount) is changed
2872      */
2873     BreakCallBack(client->host, ExistingFid, 0);
2874
2875 Bad_Link:
2876     /* Write the all modified vnodes (parent, new files) and volume back */
2877     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2878     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
2879     return errorCode;
2880
2881 } /*SAFSS_Link*/
2882
2883
2884 SRXAFS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2885     struct rx_call *acall;               /* Rx call */
2886     struct AFSFid *DirFid;               /* Parent dir's fid */
2887     char *Name;                          /* File name to create */
2888     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2889     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2890     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2891     struct AFSVolSync *Sync;
2892 {
2893     afs_int32 code;
2894     struct rx_connection *tcon;
2895 #if FS_STATS_DETAILED
2896     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2897     struct timeval opStartTime,
2898                    opStopTime;              /* Start/stop times for RPC op*/
2899     struct timeval elapsedTime;             /* Transfer time */
2900
2901     /*
2902      * Set our stats pointer, remember when the RPC operation started, and
2903      * tally the operation.
2904      */
2905     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
2906     FS_LOCK
2907     (opP->numOps)++;
2908     FS_UNLOCK
2909     TM_GetTimeOfDay(&opStartTime, 0);
2910 #endif /* FS_STATS_DETAILED */
2911
2912     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
2913         goto Bad_Link;
2914
2915     code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
2916                       OutDirStatus, Sync);
2917     
2918 Bad_Link:
2919     CallPostamble(tcon);
2920
2921 #if FS_STATS_DETAILED
2922     TM_GetTimeOfDay(&opStopTime, 0);
2923     if (code == 0) {
2924       FS_LOCK
2925       (opP->numSuccesses)++;
2926       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2927       fs_stats_AddTo((opP->sumTime), elapsedTime);
2928       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2929       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2930         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2931       }
2932       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2933         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2934       }
2935       FS_UNLOCK
2936     }
2937
2938 #endif /* FS_STATS_DETAILED */
2939
2940     osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
2941     return code;
2942
2943 } /*SRXAFS_Link*/
2944
2945
2946 /*
2947  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
2948  * merged into it when possible.
2949  */
2950 SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid, OutFidStatus,
2951               OutDirStatus, CallBack, Sync)
2952     struct rx_call *acall;               /* Rx call */
2953     struct AFSFid *DirFid;               /* Parent dir's fid */
2954     char *Name;                          /* Name of dir to be created */
2955     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
2956     struct AFSFid *OutFid;               /* Fid of new dir */
2957     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
2958     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2959     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
2960     struct AFSVolSync *Sync;
2961
2962 {
2963     Vnode * parentptr = 0;              /* vnode of input Directory */
2964     Vnode * targetptr = 0;              /* vnode of the new file */
2965     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2966     Volume * volptr = 0;                /* pointer to the volume header */
2967     int     errorCode = 0;              /* error code */
2968     struct acl_accessList * newACL;     /* Access list */
2969     int     newACLSize;                 /* Size of access list */
2970     DirHandle dir;                      /* Handle for dir package I/O */
2971     DirHandle parentdir;                /* Handle for dir package I/O */
2972     struct client * client;             /* pointer to client structure */
2973     afs_int32 rights, anyrights;                /* rights for this and any user */
2974     struct client *t_client;            /* tmp ptr to client data */
2975     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2976     struct rx_connection *tcon = rx_ConnectionOf(acall);
2977
2978     /* Get ptr to client data for user Id for logging */
2979     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2980     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2981     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
2982             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2983             inet_ntoa(logHostAddr), t_client->ViceId));
2984     FS_LOCK
2985     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
2986     FS_UNLOCK
2987     if (!FileNameOK(Name)) {
2988         errorCode = EINVAL;
2989         goto Bad_MakeDir;
2990     }
2991
2992     /*
2993      * Get the vnode and volume for the parent dir along with the caller's
2994      * rights to it.
2995      */
2996     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2997                                      MustBeDIR, &parentwhentargetnotdir,
2998                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2999         goto Bad_MakeDir;
3000     }
3001  
3002     /* set volume synchronization information */
3003     SetVolumeSync(Sync, volptr);
3004
3005     /* Write access to the parent directory? */
3006 #ifdef DIRCREATE_NEED_WRITE
3007     /*
3008      * requires w access for the user to create a directory. this
3009      * closes a loophole in the current security arrangement, since a
3010      * user with i access only can create a directory and get the
3011      * implcit a access that goes with dir ownership, and proceed to 
3012      * subvert quota in the volume.
3013      */
3014     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
3015         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
3016 #else 
3017     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
3018 #endif /* DIRCREATE_NEED_WRITE */ 
3019         goto Bad_MakeDir;
3020     }
3021
3022 #define EMPTYDIRBLOCKS 2
3023     /* get a new vnode and set it up */
3024     if (errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
3025                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS)) {
3026         goto Bad_MakeDir;
3027     }
3028
3029     /* Update the status for the parent dir */
3030 #if FS_STATS_DETAILED
3031     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
3032                              parentptr->disk.linkCount+1, client->InSameNetwork);
3033 #else
3034     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
3035                              parentptr->disk.linkCount+1);
3036 #endif /* FS_STATS_DETAILED */
3037
3038     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
3039     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
3040                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
3041     assert(parentwhentargetnotdir == 0);
3042     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
3043
3044     /* update the status for the target vnode */
3045     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
3046                              parentptr, volptr, 0);
3047
3048     /* Actually create the New directory in the directory package */
3049     SetDirHandle(&dir, targetptr);
3050     assert(!(MakeDir(&dir, OutFid, DirFid)));
3051     DFlush();
3052     targetptr->disk.length = Length(&dir);
3053
3054     /* set up return status */
3055     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3056     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
3057
3058     /* convert the write lock to a read lock before breaking callbacks */
3059     VVnodeWriteToRead(&errorCode, parentptr);
3060     assert(!errorCode || errorCode == VSALVAGE);
3061
3062     /* break call back on DirFid */
3063     BreakCallBack(client->host, DirFid, 0);
3064
3065     /* Return a callback promise to caller */
3066     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3067
3068 Bad_MakeDir: 
3069     /* Write the all modified vnodes (parent, new files) and volume back */
3070     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3071     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
3072     return errorCode;
3073
3074 } /*SAFSS_MakeDir*/
3075
3076
3077 SRXAFS_MakeDir (acall, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
3078     struct rx_call *acall;               /* Rx call */
3079     struct AFSFid *DirFid;               /* Parent dir's fid */
3080     char *Name;                          /* Name of dir to be created */
3081     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
3082     struct AFSFid *OutFid;               /* Fid of new dir */
3083     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
3084     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
3085     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
3086     struct AFSVolSync *Sync;
3087 {
3088     afs_int32 code;
3089     struct rx_connection *tcon;
3090 #if FS_STATS_DETAILED
3091     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3092     struct timeval opStartTime,
3093                    opStopTime;              /* Start/stop times for RPC op*/
3094     struct timeval elapsedTime;             /* Transfer time */
3095
3096     /*
3097      * Set our stats pointer, remember when the RPC operation started, and
3098      * tally the operation.
3099      */
3100     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
3101     FS_LOCK
3102     (opP->numOps)++;
3103     FS_UNLOCK
3104     TM_GetTimeOfDay(&opStartTime, 0);
3105 #endif /* FS_STATS_DETAILED */
3106     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
3107         goto Bad_MakeDir;
3108
3109     code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
3110                          OutFidStatus, OutDirStatus, CallBack, Sync);
3111     
3112 Bad_MakeDir:
3113     CallPostamble(tcon);
3114
3115 #if FS_STATS_DETAILED
3116     TM_GetTimeOfDay(&opStopTime, 0);
3117     if (code == 0) {
3118       FS_LOCK
3119       (opP->numSuccesses)++;
3120       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3121       fs_stats_AddTo((opP->sumTime), elapsedTime);
3122       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3123       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3124         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3125       }
3126       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3127         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3128       }
3129       FS_UNLOCK
3130     }
3131
3132 #endif /* FS_STATS_DETAILED */
3133
3134     osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3135     return code;
3136
3137 } /*SRXAFS_MakeDir*/
3138
3139
3140 /*
3141  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
3142  * merged into it when possible.
3143  */
3144 SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync)
3145     struct rx_call *acall;               /* Rx call */
3146     struct AFSFid *DirFid;               /* Parent dir's fid */
3147     char *Name;                          /* (Empty) dir's name to be removed */
3148     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3149     struct AFSVolSync *Sync;
3150
3151 {
3152     Vnode * parentptr = 0;              /* vnode of input Directory */
3153     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3154     Vnode * targetptr = 0;              /* file to be deleted */
3155     AFSFid fileFid;                     /* area for Fid from the directory */
3156     int     errorCode = 0;              /* error code */
3157     DirHandle dir;                      /* Handle for dir package I/O */
3158     Volume * volptr = 0;                /* pointer to the volume header */
3159     struct client * client;             /* pointer to client structure */
3160     afs_int32 rights, anyrights;                /* rights for this and any user */
3161     Vnode debugvnode1, debugvnode2;
3162     struct client *t_client;            /* tmp ptr to client data */
3163     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3164     struct rx_connection *tcon = rx_ConnectionOf(acall);
3165
3166     /* Get ptr to client data for user Id for logging */
3167     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3168     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3169     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3170             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3171             inet_ntoa(logHostAddr), t_client->ViceId));
3172     FS_LOCK
3173     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
3174     FS_UNLOCK
3175     /*
3176      * Get the vnode and volume for the parent dir along with the caller's
3177      * rights to it
3178      */
3179     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3180                                      MustBeDIR, &parentwhentargetnotdir,
3181                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3182         goto Bad_RemoveDir;
3183     }
3184     debugvnode1 = *parentptr;
3185
3186     /* set volume synchronization information */
3187     SetVolumeSync(Sync, volptr);
3188
3189     /* Does the caller has delete (&write) access to the parent dir? */
3190     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
3191         goto Bad_RemoveDir;
3192     }
3193
3194     debugvnode2 = *parentptr;
3195     /* Do the actual delete of the desired (empty) directory, Name */
3196     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
3197                                  Name, MustBeDIR)) {
3198         goto Bad_RemoveDir;
3199     }
3200
3201     /* Update the status for the parent dir; link count is also adjusted */
3202 #if FS_STATS_DETAILED
3203     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3204                              parentptr->disk.linkCount-1, client->InSameNetwork);
3205 #else
3206     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3207                              parentptr->disk.linkCount-1);
3208 #endif /* FS_STATS_DETAILED */
3209
3210     /* Return to the caller the updated parent dir status */
3211     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
3212
3213     /*
3214      * Note: it is not necessary to break the callback on fileFid, since
3215      * refcount is now 0, so no one should be able to refer to the dir
3216      * any longer
3217      */
3218     DeleteFileCallBacks(&fileFid);
3219
3220     /* convert the write lock to a read lock before breaking callbacks */
3221     VVnodeWriteToRead(&errorCode, parentptr);
3222     assert(!errorCode || errorCode == VSALVAGE);
3223
3224     /* break call back on DirFid and fileFid */
3225     BreakCallBack(client->host, DirFid, 0);
3226
3227 Bad_RemoveDir: 
3228     /* Write the all modified vnodes (parent, new files) and volume back */
3229     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3230     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
3231     return errorCode;
3232
3233 } /*SAFSS_RemoveDir*/
3234
3235
3236 SRXAFS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync)
3237     struct rx_call *acall;               /* Rx call */
3238     struct AFSFid *DirFid;               /* Parent dir's fid */
3239     char *Name;                          /* (Empty) dir's name to be removed */
3240     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3241     struct AFSVolSync *Sync;
3242 {
3243     afs_int32 code;
3244     struct rx_connection *tcon;
3245 #if FS_STATS_DETAILED
3246     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3247     struct timeval opStartTime,
3248                    opStopTime;              /* Start/stop times for RPC op*/
3249     struct timeval elapsedTime;             /* Transfer time */
3250
3251     /*
3252      * Set our stats pointer, remember when the RPC operation started, and
3253      * tally the operation.
3254      */
3255     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
3256     FS_LOCK
3257     (opP->numOps)++;
3258     FS_UNLOCK
3259     TM_GetTimeOfDay(&opStartTime, 0);
3260 #endif /* FS_STATS_DETAILED */
3261
3262     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
3263         goto Bad_RemoveDir;
3264
3265     code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
3266     
3267 Bad_RemoveDir:
3268     CallPostamble(tcon);
3269
3270 #if FS_STATS_DETAILED
3271     TM_GetTimeOfDay(&opStopTime, 0);
3272     if (code == 0) {
3273       FS_LOCK
3274       (opP->numSuccesses)++;
3275       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3276       fs_stats_AddTo((opP->sumTime), elapsedTime);
3277       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3278       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3279         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3280       }
3281       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3282         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3283       }
3284       FS_UNLOCK
3285     }
3286
3287 #endif /* FS_STATS_DETAILED */
3288
3289     osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3290     return code;
3291
3292 } /*SRXAFS_RemoveDir*/
3293
3294
3295 /*
3296  * This routine is called exclusively by SRXAFS_SetLock(), and should be
3297  * merged into it when possible.
3298  */
3299 SAFSS_SetLock (acall, Fid, type, Sync)
3300     struct rx_call *acall; /* Rx call */
3301     struct AFSFid *Fid;         /* Fid of file to lock */
3302     ViceLockType type;          /* Type of lock (Read or write) */
3303     struct AFSVolSync *Sync;
3304
3305 {
3306     Vnode * targetptr = 0;              /* vnode of input file */
3307     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3308     int     errorCode = 0;              /* error code */
3309     Volume * volptr = 0;                /* pointer to the volume header */
3310     struct client * client;             /* pointer to client structure */
3311     afs_int32 rights, anyrights;                /* rights for this and any user */
3312     struct client *t_client;            /* tmp ptr to client data */
3313     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3314     static char * locktype[2] = {"LockRead","LockWrite"};
3315     struct rx_connection *tcon = rx_ConnectionOf(acall);
3316
3317     if (type != LockRead && type != LockWrite) {
3318         errorCode = EINVAL;
3319         goto Bad_SetLock;
3320     }
3321     /* Get ptr to client data for user Id for logging */
3322     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3323     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3324     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
3325             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
3326             inet_ntoa(logHostAddr), t_client->ViceId));
3327     FS_LOCK
3328     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
3329     FS_UNLOCK
3330
3331     /*
3332      * Get the vnode and volume for the desired file along with the caller's
3333      * rights to it
3334      */
3335     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3336                                      DONTCHECK, &parentwhentargetnotdir,
3337                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3338         goto Bad_SetLock;
3339     }
3340
3341     /* set volume synchronization information */
3342     SetVolumeSync(Sync, volptr);
3343
3344     /* Handle the particular type of set locking, type */
3345     errorCode = HandleLocking(targetptr, rights, type);
3346
3347 Bad_SetLock: 
3348     /* Write the all modified vnodes (parent, new files) and volume back */
3349     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3350
3351     if ((errorCode == VREADONLY) && (type == LockRead))
3352        errorCode = 0;  /* allow read locks on RO volumes without saving state */
3353
3354     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
3355     return(errorCode);
3356
3357 }  /*SAFSS_SetLock*/
3358
3359
3360 SRXAFS_OldSetLock(acall, Fid, type, Sync)
3361     struct rx_call *acall;      /* Rx call */
3362     struct AFSFid *Fid;         /* Fid of file to lock */
3363     ViceLockType type;          /* Type of lock (Read or write) */
3364     struct AFSVolSync *Sync;
3365 {
3366     return SRXAFS_SetLock(acall, Fid, type, Sync);
3367
3368 } /*SRXAFS_OldSetLock*/
3369
3370
3371 SRXAFS_SetLock (acall, Fid, type, Sync)
3372     struct rx_call *acall;      /* Rx call */
3373     struct AFSFid *Fid;         /* Fid of file to lock */
3374     ViceLockType type;          /* Type of lock (Read or write) */
3375     struct AFSVolSync *Sync;
3376 {
3377     afs_int32 code;
3378     struct rx_connection *tcon;
3379 #if FS_STATS_DETAILED
3380     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3381     struct timeval opStartTime,
3382                    opStopTime;              /* Start/stop times for RPC op*/
3383     struct timeval elapsedTime;             /* Transfer time */
3384
3385     /*
3386      * Set our stats pointer, remember when the RPC operation started, and
3387      * tally the operation.
3388      */
3389     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
3390     FS_LOCK
3391     (opP->numOps)++;
3392     FS_UNLOCK
3393     TM_GetTimeOfDay(&opStartTime, 0);
3394 #endif /* FS_STATS_DETAILED */
3395
3396     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
3397         goto Bad_SetLock;
3398
3399     code = SAFSS_SetLock (acall, Fid, type, Sync);
3400     
3401 Bad_SetLock:
3402     CallPostamble(tcon);
3403
3404 #if FS_STATS_DETAILED
3405     TM_GetTimeOfDay(&opStopTime, 0); 
3406     if (code == 0) {
3407       FS_LOCK
3408       (opP->numSuccesses)++;
3409       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3410       fs_stats_AddTo((opP->sumTime), elapsedTime);
3411       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3412       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3413         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3414       }
3415       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3416         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3417       }
3418       FS_UNLOCK
3419     }
3420 #endif /* FS_STATS_DETAILED */
3421
3422     osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
3423     return code;
3424
3425 } /*SRXAFS_SetLock*/
3426
3427
3428 /*
3429  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
3430  * merged into it when possible.
3431  */
3432 SAFSS_ExtendLock (acall, Fid, Sync)
3433     struct rx_call *acall;      /* Rx call */
3434     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3435     struct AFSVolSync *Sync;
3436
3437 {
3438     Vnode * targetptr = 0;              /* vnode of input file */
3439     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3440     int     errorCode = 0;              /* error code */
3441     Volume * volptr = 0;                /* pointer to the volume header */
3442     struct client * client;             /* pointer to client structure */
3443     afs_int32 rights, anyrights;                /* rights for this and any user */
3444     struct client *t_client;            /* tmp ptr to client data */
3445     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3446     struct rx_connection *tcon = rx_ConnectionOf(acall);
3447
3448     /* Get ptr to client data for user Id for logging */
3449     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3450     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3451     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
3452                Fid->Volume, Fid->Vnode, Fid->Unique, 
3453                inet_ntoa(logHostAddr), t_client->ViceId));
3454     FS_LOCK
3455     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
3456     FS_UNLOCK
3457     /*
3458      * Get the vnode and volume for the desired file along with the caller's
3459      * rights to it
3460      */
3461     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3462                                      DONTCHECK, &parentwhentargetnotdir,
3463                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3464         goto Bad_ExtendLock;
3465     }
3466
3467     /* set volume synchronization information */
3468     SetVolumeSync(Sync, volptr);
3469
3470     /* Handle the actual lock extension */
3471     errorCode = HandleLocking(targetptr, rights, LockExtend);
3472
3473 Bad_ExtendLock: 
3474     /* Put back file's vnode and volume */
3475     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3476
3477     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
3478        errorCode = 0;              /* under our generous policy re RO vols */
3479
3480     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
3481     return(errorCode);
3482
3483 } /*SAFSS_ExtendLock*/
3484
3485
3486 SRXAFS_OldExtendLock (acall, Fid, Sync)
3487     struct rx_call *acall;      /* Rx call */
3488     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3489     struct AFSVolSync *Sync;
3490 {
3491     return SRXAFS_ExtendLock(acall, Fid, Sync);
3492
3493 } /*SRXAFS_OldExtendLock*/
3494
3495
3496 SRXAFS_ExtendLock (acall, Fid, Sync)
3497     struct rx_call *acall;      /* Rx call */
3498     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3499     struct AFSVolSync *Sync;
3500 {
3501     afs_int32 code;
3502     struct rx_connection *tcon;
3503 #if FS_STATS_DETAILED
3504     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3505     struct timeval opStartTime,
3506                    opStopTime;              /* Start/stop times for RPC op*/
3507     struct timeval elapsedTime;             /* Transfer time */
3508
3509     /*
3510      * Set our stats pointer, remember when the RPC operation started, and
3511      * tally the operation.
3512      */
3513     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
3514     FS_LOCK
3515     (opP->numOps)++;
3516     FS_UNLOCK
3517     TM_GetTimeOfDay(&opStartTime, 0);
3518 #endif /* FS_STATS_DETAILED */
3519
3520     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
3521         goto Bad_ExtendLock;
3522
3523     code = SAFSS_ExtendLock (acall, Fid, Sync);
3524
3525 Bad_ExtendLock:
3526     CallPostamble(tcon);
3527
3528 #if FS_STATS_DETAILED
3529     TM_GetTimeOfDay(&opStopTime, 0);
3530     if (code == 0) {
3531       FS_LOCK
3532       (opP->numSuccesses)++;
3533       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3534       fs_stats_AddTo((opP->sumTime), elapsedTime);
3535       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3536       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3537         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3538       }
3539       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3540         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3541       }
3542       FS_UNLOCK
3543     }
3544
3545 #endif /* FS_STATS_DETAILED */
3546
3547     osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
3548     return code;
3549
3550 } /*SRXAFS_ExtendLock*/
3551
3552
3553 /*
3554  * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
3555  * merged into it when possible.
3556  */
3557 SAFSS_ReleaseLock (acall, Fid, Sync)
3558     struct rx_call *acall;      /* Rx call */
3559     struct AFSFid *Fid;         /* Fid of file to release lock */
3560     struct AFSVolSync *Sync;
3561
3562 {
3563     Vnode * targetptr = 0;              /* vnode of input file */
3564     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3565     int     errorCode = 0;              /* error code */
3566     Volume * volptr = 0;                /* pointer to the volume header */
3567     struct client * client;             /* pointer to client structure */
3568     afs_int32 rights, anyrights;                /* rights for this and any user */
3569     struct client *t_client;            /* tmp ptr to client data */
3570     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3571     struct rx_connection *tcon = rx_ConnectionOf(acall);
3572
3573     /* Get ptr to client data for user Id for logging */
3574     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3575     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3576     ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
3577             Fid->Volume, Fid->Vnode, Fid->Unique,
3578             inet_ntoa(logHostAddr), t_client->ViceId));
3579     FS_LOCK
3580     AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
3581     FS_UNLOCK
3582     /*
3583      * Get the vnode and volume for the desired file along with the caller's
3584      * rights to it
3585      */
3586     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3587                                      DONTCHECK, &parentwhentargetnotdir,
3588                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3589         goto Bad_ReleaseLock;
3590     }
3591
3592     /* set volume synchronization information */
3593     SetVolumeSync(Sync, volptr);
3594
3595     /* Handle the actual lock release */
3596     if (errorCode = HandleLocking(targetptr, rights, LockRelease))
3597         goto Bad_ReleaseLock;
3598
3599     /* if no more locks left, a callback would be triggered here */
3600     if (targetptr->disk.lock.lockCount <= 0) {
3601         /* convert the write lock to a read lock before breaking callbacks */
3602         VVnodeWriteToRead(&errorCode, targetptr);
3603         assert(!errorCode || errorCode == VSALVAGE);
3604         BreakCallBack(client->host, Fid, 0);
3605     }
3606
3607 Bad_ReleaseLock: 
3608     /* Put back file's vnode and volume */
3609     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3610
3611     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
3612        errorCode = 0;              /* under our generous policy re RO vols */
3613
3614     ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
3615     return(errorCode);
3616
3617 } /*SAFSS_ReleaseLock*/
3618
3619
3620 SRXAFS_OldReleaseLock (acall, Fid, Sync)
3621     struct rx_call *acall;      /* Rx call */
3622     struct AFSFid *Fid;         /* Fid of file to release lock */
3623     struct AFSVolSync *Sync;
3624 {
3625     return SRXAFS_ReleaseLock(acall, Fid, Sync);
3626
3627 } /*SRXAFS_OldReleaseLock*/
3628
3629
3630 SRXAFS_ReleaseLock (acall, Fid, Sync)
3631     struct rx_call *acall;      /* Rx call */
3632     struct AFSFid *Fid;         /* Fid of file to release lock */
3633     struct AFSVolSync *Sync;
3634 {
3635     afs_int32 code;
3636     struct rx_connection *tcon;
3637 #if FS_STATS_DETAILED
3638     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3639     struct timeval opStartTime,
3640                    opStopTime;              /* Start/stop times for RPC op*/
3641     struct timeval elapsedTime;             /* Transfer time */
3642
3643     /*
3644      * Set our stats pointer, remember when the RPC operation started, and
3645      * tally the operation.
3646      */
3647     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
3648     FS_LOCK
3649     (opP->numOps)++;
3650     FS_UNLOCK
3651     TM_GetTimeOfDay(&opStartTime, 0);
3652 #endif /* FS_STATS_DETAILED */
3653
3654     if (code = CallPreamble(acall, ACTIVECALL, &tcon))
3655         goto Bad_ReleaseLock;
3656
3657     code = SAFSS_ReleaseLock (acall, Fid, Sync);
3658     
3659 Bad_ReleaseLock:
3660     CallPostamble(tcon);
3661
3662 #if FS_STATS_DETAILED
3663     TM_GetTimeOfDay(&opStopTime, 0);
3664     if (code == 0) {
3665       FS_LOCK
3666       (opP->numSuccesses)++;
3667       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3668       fs_stats_AddTo((opP->sumTime), elapsedTime);
3669       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3670       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3671         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3672       }
3673       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3674         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3675       }
3676       FS_UNLOCK
3677     }
3678
3679 #endif /* FS_STATS_DETAILED */
3680
3681     osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
3682     return code;
3683
3684 } /*SRXAFS_ReleaseLock*/
3685
3686
3687 /*
3688  * This routine is called exclusively by SRXAFS_GetStatistics(), and should be
3689  * merged into it when possible.
3690  */
3691 static GetStatistics (acall, Statistics)
3692     struct rx_call *acall;            /* Rx call */
3693     struct AFSStatistics *Statistics; /* Placeholder for returned AFS statistics */
3694 {
3695     ViceLog(1, ("SAFS_GetStatistics Received\n"));
3696     FS_LOCK
3697     AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
3698     FS_UNLOCK
3699     memset(Statistics, 0, sizeof(*Statistics));
3700     SetAFSStats(Statistics);
3701     SetVolumeStats(Statistics);
3702     SetSystemStats(Statistics);
3703
3704     return(0);
3705
3706 } /*GetStatistics*/
3707
3708
3709 SRXAFS_GetStatistics (acall, Statistics)
3710     struct rx_call *acall;            /* Rx call */
3711     struct ViceStatistics *Statistics; /* Placeholder for returned AFS statistics */
3712
3713 {
3714     afs_int32 code;
3715     struct rx_connection *tcon;
3716 #if FS_STATS_DETAILED
3717     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3718     struct timeval opStartTime,
3719                    opStopTime;              /* Start/stop times for RPC op*/
3720     struct timeval elapsedTime;             /* Transfer time */
3721
3722     /*
3723      * Set our stats pointer, remember when the RPC operation started, and
3724      * tally the operation.
3725      */
3726     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
3727     FS_LOCK
3728     (opP->numOps)++;
3729     FS_UNLOCK
3730     TM_GetTimeOfDay(&opStartTime, 0);
3731 #endif /* FS_STATS_DETAILED */
3732
3733     if (code = CallPreamble(acall, NOTACTIVECALL, &tcon))
3734         goto Bad_GetStatistics;
3735
3736     code = GetStatistics (tcon, Statistics);
3737     
3738 Bad_GetStatistics:
3739     CallPostamble(tcon);
3740
3741 #if FS_STATS_DETAILED
3742     TM_GetTimeOfDay(&opStopTime, 0);
3743     if (code == 0) {
3744       FS_LOCK
3745       (opP->numSuccesses)++;
3746       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3747       fs_stats_AddTo((opP->sumTime), elapsedTime);
3748       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3749       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3750         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3751       }
3752       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3753         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3754       }
3755       FS_UNLOCK
3756     }
3757 #endif /* FS_STATS_DETAILED */
3758
3759     return code;
3760
3761 } /*SRXAFS_GetStatistics*/
3762
3763
3764 /*------------------------------------------------------------------------
3765  * EXPORTED SRXAFS_XStatsVersion
3766  *
3767  * Description:
3768  *      Routine called by the server-side RPC interface to implement
3769  *      pulling out the xstat version number for the File Server.
3770  *
3771  * Arguments:
3772  *      a_versionP : Ptr to the version number variable to set.
3773  *
3774  * Returns:
3775  *      0 (always)
3776  *
3777  * Environment:
3778  *      Nothing interesting.
3779  *
3780  * Side Effects:
3781  *      As advertised.
3782  *------------------------------------------------------------------------*/
3783
3784 int SRXAFS_XStatsVersion(a_call, a_versionP)
3785     struct rx_call *a_call;
3786     afs_int32 *a_versionP;
3787
3788 { /*SRXAFS_XStatsVersion*/
3789
3790 #if FS_STATS_DETAILED
3791     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3792     struct timeval opStartTime,
3793                    opStopTime;              /* Start/stop times for RPC op*/
3794     struct timeval elapsedTime;             /* Transfer time */
3795
3796     /*
3797      * Set our stats pointer, remember when the RPC operation started, and
3798      * tally the operation.
3799      */
3800     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
3801     FS_LOCK
3802     (opP->numOps)++;
3803     FS_UNLOCK
3804     TM_GetTimeOfDay(&opStartTime, 0);
3805 #endif /* FS_STATS_DETAILED */
3806
3807     *a_versionP = AFS_XSTAT_VERSION;
3808
3809 #if FS_STATS_DETAILED
3810     TM_GetTimeOfDay(&opStopTime, 0);
3811     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3812     fs_stats_AddTo((opP->sumTime), elapsedTime);
3813     fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3814     if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3815         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3816     }
3817     if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3818         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3819     }
3820     FS_LOCK
3821     (opP->numSuccesses)++;
3822     FS_UNLOCK
3823 #endif /* FS_STATS_DETAILED */
3824
3825     return(0);
3826
3827 }  /*SRXAFS_XStatsVersion*/
3828
3829
3830 /*------------------------------------------------------------------------
3831  * PRIVATE FillPerfValues
3832  *
3833  * Description:
3834  *      Routine called to fill a regular performance data structure.
3835  *
3836  * Arguments:
3837  *      a_perfP : Ptr to perf structure to fill
3838  *
3839  * Returns:
3840  *      Nothing.
3841  *
3842  * Environment:
3843  *      Various collections need this info, so the guts were put in
3844  *      this separate routine.
3845  *
3846  * Side Effects:
3847  *      As advertised.
3848  *------------------------------------------------------------------------*/
3849
3850 static void FillPerfValues(a_perfP)
3851     struct afs_PerfStats *a_perfP;
3852
3853 { /*FillPerfValues*/
3854
3855     int dir_Buffers;            /*# buffers in use by dir package*/
3856     int dir_Calls;              /*# read calls in dir package*/
3857     int dir_IOs;                /*# I/O ops in dir package*/
3858
3859     /*
3860      * Vnode cache section.
3861      */
3862     a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
3863     a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
3864     a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
3865     a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
3866     a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
3867     a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
3868     a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
3869     a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
3870     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
3871     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
3872     a_perfP->vcache_H_Entries = VolumeCacheSize;
3873     a_perfP->vcache_H_Gets = VolumeGets;
3874     a_perfP->vcache_H_Replacements = VolumeReplacements;
3875     
3876     /*
3877      * Directory section.
3878      */
3879     DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
3880     a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
3881     a_perfP->dir_Calls = (afs_int32 )dir_Calls;
3882     a_perfP->dir_IOs = (afs_int32) dir_IOs;
3883     
3884     /*
3885      * Rx section.
3886      */
3887     a_perfP->rx_packetRequests =
3888         (afs_int32) rx_stats.packetRequests;
3889     a_perfP->rx_noPackets_RcvClass =
3890         (afs_int32) rx_stats.receivePktAllocFailures;
3891     a_perfP->rx_noPackets_SendClass =
3892         (afs_int32) rx_stats.sendPktAllocFailures;
3893     a_perfP->rx_noPackets_SpecialClass =
3894         (afs_int32) rx_stats.specialPktAllocFailures;
3895     a_perfP->rx_socketGreedy =
3896         (afs_int32) rx_stats.socketGreedy;
3897     a_perfP->rx_bogusPacketOnRead =
3898         (afs_int32) rx_stats.bogusPacketOnRead;
3899     a_perfP->rx_bogusHost =
3900         (afs_int32) rx_stats.bogusHost;
3901     a_perfP->rx_noPacketOnRead =
3902         (afs_int32) rx_stats.noPacketOnRead;
3903     a_perfP->rx_noPacketBuffersOnRead =
3904         (afs_int32) rx_stats.noPacketBuffersOnRead;
3905     a_perfP->rx_selects =
3906         (afs_int32) rx_stats.selects;
3907     a_perfP->rx_sendSelects =
3908         (afs_int32) rx_stats.sendSelects;
3909     a_perfP->rx_packetsRead_RcvClass =
3910         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
3911     a_perfP->rx_packetsRead_SendClass =
3912         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
3913     a_perfP->rx_packetsRead_SpecialClass =
3914         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
3915     a_perfP->rx_dataPacketsRead =
3916         (afs_int32) rx_stats.dataPacketsRead;
3917     a_perfP->rx_ackPacketsRead =
3918         (afs_int32) rx_stats.ackPacketsRead;
3919     a_perfP->rx_dupPacketsRead =
3920         (afs_int32) rx_stats.dupPacketsRead;
3921     a_perfP->rx_spuriousPacketsRead =
3922         (afs_int32) rx_stats.spuriousPacketsRead;
3923     a_perfP->rx_packetsSent_RcvClass =
3924         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
3925     a_perfP->rx_packetsSent_SendClass =
3926         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
3927     a_perfP->rx_packetsSent_SpecialClass =
3928         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
3929     a_perfP->rx_ackPacketsSent =
3930         (afs_int32) rx_stats.ackPacketsSent;
3931     a_perfP->rx_pingPacketsSent =
3932         (afs_int32) rx_stats.pingPacketsSent;
3933     a_perfP->rx_abortPacketsSent =
3934         (afs_int32) rx_stats.abortPacketsSent;
3935     a_perfP->rx_busyPacketsSent =
3936         (afs_int32) rx_stats.busyPacketsSent;
3937     a_perfP->rx_dataPacketsSent =
3938         (afs_int32) rx_stats.dataPacketsSent;
3939     a_perfP->rx_dataPacketsReSent =
3940         (afs_int32) rx_stats.dataPacketsReSent;
3941     a_perfP->rx_dataPacketsPushed =
3942         (afs_int32) rx_stats.dataPacketsPushed;
3943     a_perfP->rx_ignoreAckedPacket =
3944         (afs_int32) rx_stats.ignoreAckedPacket;
3945     a_perfP->rx_totalRtt_Sec =
3946         (afs_int32) rx_stats.totalRtt.sec;
3947     a_perfP->rx_totalRtt_Usec =
3948         (afs_int32) rx_stats.totalRtt.usec;
3949     a_perfP->rx_minRtt_Sec =
3950         (afs_int32) rx_stats.minRtt.sec;
3951     a_perfP->rx_minRtt_Usec =
3952         (afs_int32) rx_stats.minRtt.usec;
3953     a_perfP->rx_maxRtt_Sec =
3954         (afs_int32) rx_stats.maxRtt.sec;
3955     a_perfP->rx_maxRtt_Usec =
3956         (afs_int32) rx_stats.maxRtt.usec;
3957     a_perfP->rx_nRttSamples =
3958         (afs_int32) rx_stats.nRttSamples;
3959     a_perfP->rx_nServerConns =
3960         (afs_int32) rx_stats.nServerConns;
3961     a_perfP->rx_nClientConns =
3962         (afs_int32) rx_stats.nClientConns;
3963     a_perfP->rx_nPeerStructs =
3964         (afs_int32) rx_stats.nPeerStructs;
3965     a_perfP->rx_nCallStructs =
3966         (afs_int32) rx_stats.nCallStructs;
3967     a_perfP->rx_nFreeCallStructs =
3968         (afs_int32) rx_stats.nFreeCallStructs;
3969     
3970     a_perfP->host_NumHostEntries = HTs;
3971     a_perfP->host_HostBlocks = HTBlocks;
3972     h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
3973                       &(a_perfP->host_HostsInSameNetOrSubnet),
3974                       &(a_perfP->host_HostsInDiffSubnet),
3975                       &(a_perfP->host_HostsInDiffNetwork));
3976     a_perfP->host_NumClients = CEs;
3977     a_perfP->host_ClientBlocks = CEBlocks;
3978     
3979     a_perfP->sysname_ID = afs_perfstats.sysname_ID;
3980
3981 } /*FillPerfValues*/
3982
3983
3984 /*------------------------------------------------------------------------
3985  * EXPORTED SRXAFS_GetXStats
3986  *
3987  * Description:
3988  *      Routine called by the server-side callback RPC interface to
3989  *      implement getting the given data collection from the extended
3990  *      File Server statistics.
3991  *
3992  * Arguments:
3993  *      a_call              : Ptr to Rx call on which this request came in.
3994  *      a_clientVersionNum  : Client version number.
3995  *      a_opCode            : Desired operation.
3996  *      a_serverVersionNumP : Ptr to version number to set.
3997  *      a_timeP             : Ptr to time value (seconds) to set.
3998  *      a_dataP             : Ptr to variable array structure to return
3999  *                            stuff in.
4000  *
4001  * Returns:
4002  *      0 (always).
4003  *
4004  * Environment:
4005  *      Nothing interesting.
4006  *
4007  * Side Effects:
4008  *      As advertised.
4009  *------------------------------------------------------------------------*/
4010
4011 int SRXAFS_GetXStats(a_call, a_clientVersionNum, a_collectionNumber, a_srvVersionNumP, a_timeP, a_dataP)
4012     struct rx_call *a_call;
4013     afs_int32 a_clientVersionNum;
4014     afs_int32 a_collectionNumber;
4015     afs_int32 *a_srvVersionNumP;
4016     afs_int32 *a_timeP;
4017     AFS_CollData *a_dataP;
4018
4019 { /*SRXAFS_GetXStats*/
4020
4021     register int code;          /*Return value*/
4022     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
4023     afs_int32 dataBytes;                /*Bytes in data buffer*/
4024 #if FS_STATS_DETAILED
4025     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4026     struct timeval opStartTime,
4027                    opStopTime;              /* Start/stop times for RPC op*/
4028     struct timeval elapsedTime;             /* Transfer time */
4029
4030     /*
4031      * Set our stats pointer, remember when the RPC operation started, and
4032      * tally the operation.
4033      */
4034     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
4035     FS_LOCK
4036     (opP->numOps)++;
4037     FS_UNLOCK
4038     TM_GetTimeOfDay(&opStartTime, 0);
4039 #endif /* FS_STATS_DETAILED */
4040
4041     /*
4042      * Record the time of day and the server version number.
4043      */
4044     *a_srvVersionNumP = AFS_XSTAT_VERSION;
4045     *a_timeP = FT_ApproxTime();
4046
4047     /*
4048      * Stuff the appropriate data in there (assume victory)
4049      */
4050     code = 0;
4051
4052     ViceLog(1, ("Received GetXStats call for collection %d\n",  a_collectionNumber));
4053
4054 #if 0
4055     /*
4056      * We're not keeping stats, so just return successfully with
4057      * no data.
4058      */
4059     a_dataP->AFS_CollData_len = 0;
4060     a_dataP->AFS_CollData_val = (afs_int32 *)0;
4061 #endif /* 0 */
4062
4063     switch(a_collectionNumber) {
4064       case AFS_XSTATSCOLL_CALL_INFO:
4065         /*
4066          * Pass back all the call-count-related data.
4067          *
4068          * >>> We are forced to allocate a separate area in which to
4069          * >>> put this stuff in by the RPC stub generator, since it
4070          * >>> will be freed at the tail end of the server stub code.
4071          */
4072 #if 0
4073         /*
4074          * I don't think call-level stats are being collected yet
4075          * for the File Server.
4076          */
4077         dataBytes = sizeof(struct afs_Stats);
4078         dataBuffP = (afs_int32 *)malloc(dataBytes);
4079         memcpy(dataBuffP, &afs_cmstats, dataBytes);
4080         a_dataP->AFS_CollData_len = dataBytes>>2;
4081         a_dataP->AFS_CollData_val = dataBuffP;
4082 #else
4083         a_dataP->AFS_CollData_len = 0;
4084         a_dataP->AFS_CollData_val = (afs_int32 *)0;
4085 #endif /* 0 */
4086         break;
4087
4088       case AFS_XSTATSCOLL_PERF_INFO:
4089         /*
4090          * Pass back all the regular performance-related data.
4091          *
4092          * >>> We are forced to allocate a separate area in which to
4093          * >>> put this stuff in by the RPC stub generator, since it
4094          * >>> will be freed at the tail end of the server stub code.
4095          */
4096
4097         afs_perfstats.numPerfCalls++;
4098         FillPerfValues(&afs_perfstats);
4099
4100         /*
4101          * Don't overwrite the spares at the end.
4102          */
4103
4104         dataBytes = sizeof(struct afs_PerfStats);
4105         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
4106         memcpy(dataBuffP, &afs_perfstats, dataBytes);
4107         a_dataP->AFS_CollData_len = dataBytes>>2;
4108         a_dataP->AFS_CollData_val = dataBuffP;
4109         break;
4110
4111       case AFS_XSTATSCOLL_FULL_PERF_INFO:
4112         /*
4113          * Pass back the full collection of performance-related data.
4114          * We have to stuff the basic, overall numbers in, but the
4115          * detailed numbers are kept in the structure already.
4116          *
4117          * >>> We are forced to allocate a separate area in which to
4118          * >>> put this stuff in by the RPC stub generator, since it
4119          * >>> will be freed at the tail end of the server stub code.
4120          */
4121
4122         afs_perfstats.numPerfCalls++;
4123 #if FS_STATS_DETAILED
4124         afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
4125         FillPerfValues(&afs_FullPerfStats.overall);
4126
4127         /*
4128          * Don't overwrite the spares at the end.
4129          */
4130
4131         dataBytes = sizeof(struct fs_stats_FullPerfStats);
4132         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
4133         memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
4134         a_dataP->AFS_CollData_len = dataBytes>>2;
4135         a_dataP->AFS_CollData_val = dataBuffP;
4136 #endif
4137         break;
4138
4139       default:
4140         /*
4141          * Illegal collection number.
4142          */
4143         a_dataP->AFS_CollData_len = 0;
4144         a_dataP->AFS_CollData_val = (afs_int32 *)0;
4145         code = 1;
4146     } /*Switch on collection number*/
4147
4148 #if FS_STATS_DETAILED
4149     TM_GetTimeOfDay(&opStopTime, 0);
4150     if (code == 0) {
4151       FS_LOCK
4152       (opP->numSuccesses)++;
4153       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4154       fs_stats_AddTo((opP->sumTime), elapsedTime);
4155       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4156       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4157         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4158       }
4159       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4160         fs_stats_TimeAssign((opP->maxTime), elapsedTime);