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