2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* afs_fileprocs.c - Complete File Server request routines */
12 /* Information Technology Center */
13 /* Carnegie Mellon University */
17 /* Function - A set of routines to handle the various file Server */
18 /* requests; these routines are invoked by rxgen. */
20 /* ********************************************************************** */
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
28 #include <afsconfig.h>
29 #include <afs/param.h>
37 #undef SHARED /* XXX */
42 #include <sys/param.h>
44 #include <netinet/in.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
57 #ifndef AFS_LINUX20_ENV
59 #include <netinet/if_ether.h>
63 /* included early because of name conflict on IOPEN */
64 #include <sys/inode.h>
68 #endif /* AFS_HPUX_ENV */
72 #include <afs/assert.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>
82 #include <afs/ptclient.h>
83 #include <afs/prs_fs.h>
85 #include <rx/rx_globals.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)
90 #if !defined(AFS_NT40_ENV)
93 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
95 #include <sys/statfs.h>
96 #include <sys/lockf.h>
98 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
103 #include <afs/cellconfig.h>
104 #include <afs/keys.h>
106 #include <afs/auth.h>
108 #include <afs/partition.h>
109 #include "viced_prototypes.h"
112 #include <afs/audit.h>
113 #include <afs/afsutil.h>
115 #ifdef AFS_PTHREAD_ENV
116 pthread_mutex_t fileproc_glock_mutex;
117 #endif /* AFS_PTHREAD_ENV */
120 /* Useful local defines used by this module */
123 #define MustNOTBeDIR 1
127 #define TVS_SSTATUS 2
130 #define TVS_MKDIR 0x10
132 #define CHK_FETCH 0x10
133 #define CHK_FETCHDATA 0x10
134 #define CHK_FETCHACL 0x11
135 #define CHK_FETCHSTATUS 0x12
136 #define CHK_STOREDATA 0x00
137 #define CHK_STOREACL 0x01
138 #define CHK_STORESTATUS 0x02
140 #define OWNERREAD 0400
141 #define OWNERWRITE 0200
142 #define OWNEREXEC 0100
143 #ifdef USE_GROUP_PERMS
144 #define GROUPREAD 0040
145 #define GROUPWRITE 0020
146 #define GROUPREXEC 0010
149 /* The following errors were not defined in NT. They are given unique
150 * names here to avoid any potential collision.
152 #define FSERR_ELOOP 90
153 #define FSERR_EOPNOTSUPP 122
154 #define FSERR_ECONNREFUSED 130
156 #define NOTACTIVECALL 0
159 #define CREATE_SGUID_ADMIN_ONLY 1
161 extern struct afsconf_dir *confDir;
162 extern afs_int32 dataVersionHigh;
165 static struct AFSCallStatistics AFSCallStats;
166 #if FS_STATS_DETAILED
167 struct fs_stats_FullPerfStats afs_FullPerfStats;
168 extern int AnonymousID;
169 #endif /* FS_STATS_DETAILED */
170 #if TRANSARC_VOL_STATS
171 static const char nullString[] = "";
172 #endif /* TRANSARC_VOL_STATS */
175 afs_int32 NothingYet;
178 struct afs_FSStats afs_fsstats;
180 void ResetDebug(), SetDebug(), Terminate();
185 afs_int32 BlocksSpare = 1024; /* allow 1 MB overruns */
187 extern afs_int32 implicitAdminRights;
188 extern afs_int32 readonlyServer;
191 * Externals used by the xstat code.
193 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
194 extern int CEs, CEBlocks;
196 extern int HTs, HTBlocks;
199 FetchData_RXStyle(Volume *volptr,
201 register struct rx_call *Call,
205 #if FS_STATS_DETAILED
206 afs_size_t *a_bytesToFetchP,
207 afs_size_t *a_bytesFetchedP
208 #endif /* FS_STATS_DETAILED */
212 StoreData_RXStyle(Volume *volptr,
215 struct client *client,
216 register struct rx_call *Call,
219 afs_offs_t FileLength,
221 #if FS_STATS_DETAILED
222 afs_size_t *a_bytesToStoreP,
223 afs_size_t *a_bytesStoredP
224 #endif /* FS_STATS_DETAILED */
227 #ifdef AFS_SGI_XFS_IOPS_ENV
228 #include <afs/xfsattrs.h>
229 static int GetLinkCount(Volume *avp, struct stat *astat)
231 if (!strcmp("xfs", astat->st_fstype)) {
232 return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
235 return astat->st_nlink;
238 #define GetLinkCount(V, S) (S)->st_nlink
241 afs_int32 SpareComp(Volume *avolp)
243 register afs_int32 temp;
247 temp = V_maxquota(avolp);
249 /* no matter; doesn't check in this case */
253 temp = (temp * PctSpare) / 100;
266 * Set the volume synchronization parameter for this volume. If it changes,
267 * the Cache Manager knows that the volume must be purged from the stat cache.
269 static void SetVolumeSync(register struct AFSVolSync *async,
270 register Volume *avol)
273 /* date volume instance was created */
276 async->spare1 = avol->header->diskstuff.creationDate;
289 * Note that this function always returns a held host, so
290 * that CallPostamble can block without the host's disappearing.
291 * Call returns rx connection in passed in *tconn
293 static int CallPreamble(register struct rx_call *acall, int activecall,
294 struct rx_connection **tconn)
297 struct client *tclient;
302 ViceLog (0, ("CallPreamble: unexpected null tconn!\n"));
305 *tconn = rx_ConnectionOf(acall);
309 tclient = h_FindClient_r(*tconn);
310 if (tclient->prfail == 1) { /* couldn't get the CPS */
312 h_ReleaseClient_r(tclient);
313 ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
317 retry_flag=0; /* Retry once */
319 /* Take down the old connection and re-read the key file */
320 ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
322 code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
325 h_ReleaseClient_r(tclient);
327 ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
331 tclient->prfail = 2; /* Means re-eval client's cps */
332 h_ReleaseClient_r(tclient);
336 thost = tclient->host;
337 tclient->LastCall = thost->LastCall = FT_ApproxTime();
338 if (activecall) /* For all but "GetTime" calls */
339 thost->ActiveCall = thost->LastCall;
342 if (thost->hostFlags & HOSTDELETED) {
343 ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
344 code = VBUSY; /* raced, so retry */
346 else if ((thost->hostFlags & VENUSDOWN) || (thost->hostFlags & HFE_LATER)){
347 if (BreakDelayedCallBacks_r(thost)) {
348 ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP. Possible network or routing failure.\n",
349 afs_inet_ntoa_r(thost->host, hoststr)));
350 if ( MultiProbeAlternateAddress_r (thost) ) {
351 ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
352 afs_inet_ntoa_r(thost->host, hoststr), thost->port));
355 ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
356 afs_inet_ntoa_r(thost->host, hoststr), thost->port));
357 if (BreakDelayedCallBacks_r(thost)) {
358 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP. Possible network or routing failure.\n",
359 afs_inet_ntoa_r(thost->host, hoststr)));
368 h_ReleaseClient_r(tclient);
376 static void CallPostamble(register struct rx_connection *aconn)
379 struct client *tclient;
382 tclient = h_FindClient_r(aconn);
383 thost = tclient->host;
384 h_ReleaseClient_r(tclient);
391 * Returns the volume and vnode pointers associated with file Fid; the lock
392 * type on the vnode is set to lock. Note that both volume/vnode's ref counts
393 * are incremented and they must be eventualy released.
396 CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock)
400 static struct timeval restartedat = {0,0};
402 if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
404 if ((*volptr) == 0) {
409 *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
414 if ((errorCode == VOFFLINE) && (VInit < 2)) {
415 /* The volume we want may not be attached yet because
416 * the volume initialization is not yet complete.
417 * We can do several things:
418 * 1. return -1, which will cause users to see
419 * "connection timed out". This is more or
420 * less the same as always, except that the servers
421 * may appear to bounce up and down while they
422 * are actually restarting.
423 * 2. return VBUSY which will cause clients to
424 * sleep and retry for 6.5 - 15 minutes, depending
425 * on what version of the CM they are running. If
426 * the file server takes longer than that interval
427 * to attach the desired volume, then the application
428 * will see an ENODEV or EIO. This approach has
429 * the advantage that volumes which have been attached
430 * are immediately available, it keeps the server's
431 * immediate backlog low, and the call is interruptible
432 * by the user. Users see "waiting for busy volume."
433 * 3. sleep here and retry. Some people like this approach
434 * because there is no danger of seeing errors. However,
435 * this approach only works with a bounded number of
436 * clients, since the pending queues will grow without
437 * stopping. It might be better to find a way to take
438 * this call and stick it back on a queue in order to
439 * recycle this thread for a different request.
440 * 4. Return a new error code, which new cache managers will
441 * know enough to interpret as "sleep and retry", without
442 * the upper bound of 6-15 minutes that is imposed by the
443 * VBUSY handling. Users will see "waiting for
444 * busy volume," so they know that something is
445 * happening. Old cache managers must be able to do
446 * something reasonable with this, for instance, mark the
447 * server down. Fortunately, any error code < 0
448 * will elicit that behavior. See #1.
449 * 5. Some combination of the above. I like doing #2 for 10
450 * minutes, followed by #4. 3.1b and 3.2 cache managers
451 * will be fine as long as the restart period is
452 * not longer than 6.5 minutes, otherwise they may
453 * return ENODEV to users. 3.3 cache managers will be
454 * fine for 10 minutes, then will return
455 * ETIMEDOUT. 3.4 cache managers will just wait
456 * until the call works or fails definitively.
457 * NB. The problem with 2,3,4,5 is that old clients won't
458 * fail over to an alternate read-only replica while this
459 * server is restarting. 3.4 clients will fail over right away.
461 if (restartedat.tv_sec == 0) {
462 /* I'm not really worried about when we restarted, I'm */
463 /* just worried about when the first VBUSY was returned. */
464 TM_GetTimeOfDay(&restartedat, 0);
469 TM_GetTimeOfDay(&now, 0);
470 if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
474 return (VRESTARTING);
478 /* allow read operations on busy volume */
479 else if(errorCode==VBUSY && lock==READ_LOCK) {
490 *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
493 if ((*vptr)->disk.uniquifier != fid->Unique) {
494 VPutVnode(&fileCode, *vptr);
495 assert(fileCode == 0);
497 return(VNOVNODE); /* return the right error code, at least */
503 * This routine returns the ACL associated with the targetptr. If the
504 * targetptr isn't a directory, we access its parent dir and get the ACL
505 * thru the parent; in such case the parent's vnode is returned in
509 SetAccessList(Vnode **targetptr,
511 struct acl_accessList **ACL,
517 if ((*targetptr)->disk.type == vDirectory) {
519 *ACL = VVnodeACL(*targetptr);
520 *ACLSize = VAclSize(*targetptr);
529 parentvnode = (*targetptr)->disk.parent;
530 VPutVnode(&errorCode,*targetptr);
532 if (errorCode) return(errorCode);
533 *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
534 if (errorCode) return(errorCode);
535 *ACL = VVnodeACL(*parent);
536 *ACLSize = VAclSize(*parent);
537 if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
539 if ((*targetptr)->disk.parent != parentvnode) {
540 VPutVnode(&errorCode, *parent);
542 if (errorCode) return(errorCode);
551 * Compare the directory's ACL with the user's access rights in the client
552 * connection and return the user's and everybody else's access permissions
553 * in rights and anyrights, respectively
556 GetRights (struct client *client,
557 struct acl_accessList *ACL,
559 afs_int32 *anyrights)
561 extern prlist SystemAnyUserCPS;
562 afs_int32 hrights = 0;
565 if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
567 ViceLog(0,("CheckRights failed\n"));
571 acl_CheckRights(ACL, &client->CPS, rights);
573 /* wait if somebody else is already doing the getCPS call */
575 while ( client->host->hostFlags & HCPS_INPROGRESS )
577 client->host->hostFlags |= HCPS_WAITING; /* I am waiting */
578 #ifdef AFS_PTHREAD_ENV
579 pthread_cond_wait(&client->host->cond, &host_glock_mutex);
580 #else /* AFS_PTHREAD_ENV */
581 if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
582 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
583 #endif /* AFS_PTHREAD_ENV */
586 if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
587 ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
589 acl_CheckRights(ACL, &client->host->hcps, &hrights);
591 /* Allow system:admin the rights given with the -implicit option */
592 if (acl_IsAMember(SystemId, &client->CPS))
593 *rights |= implicitAdminRights;
595 *anyrights |= hrights;
602 * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
603 * a System:Administrator)
606 VanillaUser(struct client *client)
608 if (acl_IsAMember(SystemId, &client->CPS))
609 return(0); /* not a system administrator, then you're "vanilla" */
616 * This unusual afs_int32-parameter routine encapsulates all volume package related
617 * operations together in a single function; it's called by almost all AFS
621 GetVolumePackage(struct rx_connection *tcon,
627 struct client **client,
630 afs_int32 *anyrights)
632 struct acl_accessList * aCL; /* Internal access List */
633 int aCLSize; /* size of the access list */
634 int errorCode = 0; /* return code to caller */
636 if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
639 if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
641 else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
644 if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
646 if (chkforDir == MustBeDIR) assert((*parent) == 0);
647 if ((errorCode = GetClient(tcon, client)) != 0)
651 assert(GetRights(*client, aCL, rights, anyrights) == 0);
652 /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
653 if ((*targetptr)->disk.type != vDirectory) {
654 /* anyuser can't be owner, so only have to worry about rights, not anyrights */
655 if ((*targetptr)->disk.owner == (*client)->ViceId)
656 (*rights) |= PRSFS_ADMINISTER;
658 (*rights) &= ~PRSFS_ADMINISTER;
660 #ifdef ADMIN_IMPLICIT_LOOKUP
661 /* admins get automatic lookup on everything */
662 if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
663 #endif /* ADMIN_IMPLICIT_LOOKUP */
666 } /*GetVolumePackage*/
670 * This is the opposite of GetVolumePackage(), and is always used at the end of
671 * AFS calls to put back all used vnodes and the volume in the proper order!
674 PutVolumePackage(Vnode *parentwhentargetnotdir,
679 int fileCode = 0; /* Error code returned by the volume package */
681 if (parentwhentargetnotdir) {
682 VPutVnode(&fileCode, parentwhentargetnotdir);
683 assert(!fileCode || (fileCode == VSALVAGE));
686 VPutVnode(&fileCode, targetptr);
687 assert(!fileCode || (fileCode == VSALVAGE));
690 VPutVnode(&fileCode, parentptr);
691 assert(!fileCode || (fileCode == VSALVAGE));
696 } /*PutVolumePackage*/
698 static int VolumeOwner (register struct client *client,
699 register Vnode *targetptr)
701 afs_int32 owner = V_owner(targetptr->volumePtr); /* get volume owner */
704 return (client->ViceId == owner);
707 * We don't have to check for host's cps since only regular
708 * viceid are volume owners.
710 return (acl_IsAMember(owner, &client->CPS));
715 static int VolumeRootVnode (Vnode *targetptr)
717 return ((targetptr->vnodeNumber == ROOTVNODE) &&
718 (targetptr->disk.uniquifier == 1));
720 } /*VolumeRootVnode*/
723 * Check if target file has the proper access permissions for the Fetch
724 * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
725 * StoreStatus) related calls
727 /* this code should probably just set a "priv" flag where all the audit events
728 * are now, and only generate the audit event once at the end of the routine,
729 * thus only generating the event if all the checks succeed, but only because
730 * of the privilege XXX
733 Check_PermissionRights(Vnode *targetptr,
734 struct client *client,
737 AFSStoreStatus *InStatus)
740 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
741 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
742 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
744 if (CallingRoutine & CHK_FETCH) {
746 if (VanillaUser(client))
748 if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client))
751 if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
752 if ( !(rights & PRSFS_LOOKUP)
753 #ifdef ADMIN_IMPLICIT_LOOKUP
754 /* grant admins fetch on all directories */
755 && VanillaUser(client)
756 #endif /* ADMIN_IMPLICIT_LOOKUP */
757 && !VolumeOwner(client, targetptr))
760 /* must have read access, or be owner and have insert access */
761 if (!(rights & PRSFS_READ) &&
762 !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
765 if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
766 #ifdef USE_GROUP_PERMS
767 if (!OWNSp(client, targetptr) &&
768 !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
769 errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
772 errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
777 * The check with the ownership below is a kludge to allow
778 * reading of files created with no read permission. The owner
779 * of the file is always allowed to read it.
781 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
782 errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
785 else /* !VanillaUser(client) && !FetchData */ {
786 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
787 AUD_INT, CallingRoutine, AUD_END);
790 else { /* a store operation */
791 if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
792 && (CallingRoutine != CHK_STOREACL)
793 && (targetptr->disk.type == vFile))
795 /* bypass protection checks on first store after a create
796 * for the creator; also prevent chowns during this time
797 * unless you are a system administrator */
798 /****** InStatus->Owner && UnixModeBits better be SET!! */
799 if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
802 else if (VanillaUser (client))
803 return(EPERM); /* Was EACCES */
805 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
806 AUD_INT, CallingRoutine, AUD_END);
809 if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
810 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
811 AUD_INT, CallingRoutine, AUD_END);
814 if (readonlyServer) {
817 if (CallingRoutine == CHK_STOREACL) {
818 if (!(rights & PRSFS_ADMINISTER) &&
819 !VolumeOwner(client, targetptr)) return(EACCES);
821 else { /* store data or status */
822 /* watch for chowns and chgrps */
823 if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
826 else if (VanillaUser (client))
827 return(EPERM); /* Was EACCES */
829 osi_audit(PrivilegeEvent, 0,
830 AUD_INT, (client ? client->ViceId : 0),
831 AUD_INT, CallingRoutine, AUD_END);
833 /* must be sysadmin to set suid/sgid bits */
834 if ((InStatus->Mask & AFS_SETMODE) &&
836 (InStatus->UnixModeBits & 0xc00) != 0) {
838 (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
842 if (VanillaUser(client))
844 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
845 AUD_INT, CallingRoutine, AUD_END);
847 if (CallingRoutine == CHK_STOREDATA) {
850 if (!(rights & PRSFS_WRITE))
852 /* Next thing is tricky. We want to prevent people
853 * from writing files sans 0200 bit, but we want
854 * creating new files with 0444 mode to work. We
855 * don't check the 0200 bit in the "you are the owner"
856 * path above, but here we check the bit. However, if
857 * you're a system administrator, we ignore the 0200
858 * bit anyway, since you may have fchowned the file,
860 #ifdef USE_GROUP_PERMS
861 if ((targetptr->disk.type == vFile)
862 && VanillaUser(client)) {
863 if (!OWNSp(client, targetptr) &&
864 !acl_IsAMember(targetptr->disk.owner,
866 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
869 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
874 if ((targetptr->disk.type != vDirectory)
875 && (!(targetptr->disk.modeBits & OWNERWRITE)))
878 if (VanillaUser(client))
880 else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
881 AUD_INT, CallingRoutine, AUD_END);
883 else { /* a status store */
886 if (targetptr->disk.type == vDirectory) {
887 if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
890 else { /* a file or symlink */
891 if (!(rights & PRSFS_WRITE)) return(EACCES);
900 } /*Check_PermissionRights*/
904 * The Access List information is converted from its internal form in the
905 * target's vnode buffer (or its parent vnode buffer if not a dir), to an
906 * external form and returned back to the caller, via the AccessList
910 RXFetch_AccessList(Vnode *targetptr,
911 Vnode *parentwhentargetnotdir,
912 struct AFSOpaque *AccessList)
914 char * eACL; /* External access list placeholder */
916 if (acl_Externalize((targetptr->disk.type == vDirectory ?
917 VVnodeACL(targetptr) :
918 VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
921 if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
922 acl_FreeExternalACL(&eACL);
925 strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
926 AccessList->AFSOpaque_len = strlen(eACL) +1;
928 acl_FreeExternalACL(&eACL);
931 } /*RXFetch_AccessList*/
935 * The Access List information is converted from its external form in the
936 * input AccessList structure to the internal representation and copied into
937 * the target dir's vnode storage.
940 RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList)
942 struct acl_accessList * newACL; /* PlaceHolder for new access list */
944 if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
946 if ((newACL->size + 4) > VAclSize(targetptr))
948 memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
949 acl_FreeACL(&newACL);
952 } /*RXStore_AccessList*/
956 Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir,
957 struct AFSAccessList *AccessList)
959 char * eACL; /* External access list placeholder */
961 assert(acl_Externalize((targetptr->disk.type == vDirectory ?
962 VVnodeACL(targetptr) :
963 VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
964 if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
965 acl_FreeExternalACL(&eACL);
968 strcpy((char *)(AccessList->SeqBody), (char *)eACL);
969 AccessList->SeqLen = strlen(eACL) +1;
971 acl_FreeExternalACL(&eACL);
974 } /*Fetch_AccessList*/
977 * The Access List information is converted from its external form in the
978 * input AccessList structure to the internal representation and copied into
979 * the target dir's vnode storage.
982 Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList)
984 struct acl_accessList * newACL; /* PlaceHolder for new access list */
986 if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
988 if ((newACL->size + 4) > VAclSize(targetptr))
990 memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
991 acl_FreeACL(&newACL);
994 } /*Store_AccessList*/
997 /* In our current implementation, each successive data store (new file
998 * data version) creates a new inode. This function creates the new
999 * inode, copies the old inode's contents to the new one, remove the old
1000 * inode (i.e. decrement inode count -- if it's currently used the delete
1001 * will be delayed), and modify some fields (i.e. vnode's
1002 * disk.inodeNumber and cloned)
1004 #define COPYBUFFSIZE 8192
1005 static int CopyOnWrite(Vnode *targetptr, Volume *volptr)
1007 Inode ino, nearInode;
1010 register afs_size_t size;
1011 register int length;
1014 int rc; /* return code */
1015 IHandle_t *newH; /* Use until finished copying, then cp to vnode.*/
1016 FdHandle_t *targFdP; /* Source Inode file handle */
1017 FdHandle_t *newFdP; /* Dest Inode file handle */
1019 if (targetptr->disk.type == vDirectory) DFlush(); /* just in case? */
1021 VN_GET_LEN(size, targetptr);
1022 buff = (char *)malloc(COPYBUFFSIZE);
1027 ino = VN_GET_INO(targetptr);
1028 assert(VALID_INO(ino));
1029 targFdP = IH_OPEN(targetptr->handle);
1030 if (targFdP == NULL) {
1032 ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc));
1034 VTakeOffline (volptr);
1038 nearInode = VN_GET_INO(targetptr);
1039 ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1040 VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr),
1041 targetptr->vnodeNumber, targetptr->disk.uniquifier,
1042 (int)targetptr->disk.dataVersion);
1043 if (!VALID_INO(ino))
1045 ViceLog(0,("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n", volptr->partition->name, V_id(volptr), errno));
1050 IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1051 newFdP = IH_OPEN(newH);
1052 assert(newFdP != NULL);
1055 if (size > COPYBUFFSIZE) { /* more than a buffer */
1056 length = COPYBUFFSIZE;
1057 size -= COPYBUFFSIZE;
1062 rdlen = FDH_READ(targFdP, buff, length);
1063 if (rdlen == length)
1064 wrlen = FDH_WRITE(newFdP, buff, length);
1067 /* Callers of this function are not prepared to recover
1068 * from error that put the filesystem in an inconsistent
1069 * state. Make sure that we force the volume off-line if
1070 * we some error other than ENOSPC - 4.29.99)
1072 * In case we are unable to write the required bytes, and the
1073 * error code indicates that the disk is full, we roll-back to
1074 * the initial state.
1076 if((rdlen != length) || (wrlen != length))
1077 if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */
1079 ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1080 volptr->partition->name, V_id(volptr)));
1081 /* remove destination inode which was partially copied till now*/
1082 FDH_REALLYCLOSE(newFdP);
1084 FDH_REALLYCLOSE(targFdP);
1085 rc = IH_DEC(V_linkHandle(volptr), ino,
1086 V_parentId(volptr));
1088 ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1090 volptr->partition->name));
1091 VTakeOffline (volptr);
1097 ViceLog(0,("CopyOnWrite failed: volume %u in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1098 V_id(volptr), volptr->partition->name, length,
1099 rdlen, wrlen, errno));
1100 #ifdef FAST_RESTART /* if running in no-salvage, don't core the server */
1101 ViceLog(0,("CopyOnWrite failed: taking volume offline\n"));
1102 #else /* Avoid further corruption and try to get a core. */
1105 /* Decrement this inode so salvager doesn't find it. */
1106 FDH_REALLYCLOSE(newFdP);
1108 FDH_REALLYCLOSE(targFdP);
1109 rc = IH_DEC(V_linkHandle(volptr), ino,
1110 V_parentId(volptr));
1112 VTakeOffline (volptr);
1115 #ifndef AFS_PTHREAD_ENV
1117 #endif /* !AFS_PTHREAD_ENV */
1119 FDH_REALLYCLOSE(targFdP);
1120 rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1121 V_parentId(volptr)) ;
1123 IH_RELEASE(targetptr->handle);
1125 rc = FDH_SYNC(newFdP);
1128 targetptr->handle = newH;
1129 VN_SET_INO(targetptr, ino);
1130 targetptr->disk.cloned = 0;
1131 /* Internal change to vnode, no user level change to volume - def 5445 */
1132 targetptr->changed_oldTime = 1;
1134 return 0; /* success */
1139 * Common code to handle with removing the Name (file when it's called from
1140 * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1141 * given directory, parentptr.
1145 DeleteTarget(Vnode *parentptr,
1153 DirHandle childdir; /* Handle for dir package I/O */
1157 /* watch for invalid names */
1158 if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1160 if (parentptr->disk.cloned)
1162 ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1163 if ((errorCode = CopyOnWrite(parentptr, volptr)))
1165 ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode));
1170 /* check that the file is in the directory */
1171 SetDirHandle(dir, parentptr);
1172 if (Lookup(dir, Name, fileFid))
1174 fileFid->Volume = V_id(volptr);
1176 /* just-in-case check for something causing deadlock */
1177 if (fileFid->Vnode == parentptr->vnodeNumber)
1180 *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1184 if (ChkForDir == MustBeDIR) {
1185 if ((*targetptr)->disk.type != vDirectory)
1187 } else if ((*targetptr)->disk.type == vDirectory)
1190 /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/
1192 * If the uniquifiers dont match then instead of asserting
1193 * take the volume offline and return VSALVAGE
1195 if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) {
1196 VTakeOffline(volptr);
1197 errorCode = VSALVAGE;
1201 if (ChkForDir == MustBeDIR) {
1202 SetDirHandle(&childdir, *targetptr);
1203 if (IsEmpty(&childdir) != 0)
1206 (*targetptr)->delete = 1;
1207 } else if ((--(*targetptr)->disk.linkCount) == 0)
1208 (*targetptr)->delete = 1;
1209 if ((*targetptr)->delete) {
1210 if (VN_GET_INO(*targetptr)) {
1212 IH_REALLYCLOSE((*targetptr)->handle);
1213 errorCode = IH_DEC(V_linkHandle(volptr),
1214 VN_GET_INO(*targetptr),
1215 V_parentId(volptr));
1216 IH_RELEASE((*targetptr)->handle);
1217 if (errorCode == -1) {
1218 ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n",
1219 PrintInode(NULL, VN_GET_INO(*targetptr)),
1222 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
1224 if (errno != ENOENT)
1227 ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1229 VTakeOffline(volptr);
1236 VN_SET_INO(*targetptr, (Inode)0);
1238 afs_size_t adjLength;
1239 VN_GET_LEN(adjLength, *targetptr);
1240 VAdjustDiskUsage(&errorCode, volptr,
1241 -nBlocks(adjLength),
1246 (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
1248 code = Delete(dir,(char *) Name);
1250 ViceLog(0, ("Error %d deleting %s\n", code,
1251 (((*targetptr)->disk.type== Directory)?"directory":"file")));
1252 ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1254 VTakeOffline(volptr);
1255 if (!errorCode) errorCode = code;
1265 * This routine updates the parent directory's status block after the
1266 * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1267 * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1271 Update_ParentVnodeStatus(Vnode *parentptr,
1276 #if FS_STATS_DETAILED
1277 char a_inSameNetwork
1278 #endif /* FS_STATS_DETAILED */
1281 afs_offs_t newlength; /* Holds new directory length */
1282 afs_offs_t parentLength;
1284 #if FS_STATS_DETAILED
1285 Date currDate; /*Current date*/
1286 int writeIdx; /*Write index to bump*/
1287 int timeIdx; /*Authorship time index to bump*/
1288 #endif /* FS_STATS_DETAILED */
1290 parentptr->disk.dataVersion++;
1291 newlength = Length(dir);
1293 * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1294 * (create, symlink, link, makedir) so we need to check if we have enough space
1295 * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1296 * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1298 VN_GET_LEN(parentLength, parentptr);
1299 if (nBlocks(newlength) != nBlocks(parentLength)) {
1300 VAdjustDiskUsage(&errorCode, volptr,
1301 (nBlocks(newlength) - nBlocks(parentLength)),
1302 (nBlocks(newlength) - nBlocks(parentLength)));
1304 VN_SET_LEN(parentptr, newlength);
1306 #if FS_STATS_DETAILED
1308 * Update directory write stats for this volume. Note that the auth
1309 * counter is located immediately after its associated ``distance''
1312 if (a_inSameNetwork)
1313 writeIdx = VOL_STATS_SAME_NET;
1315 writeIdx = VOL_STATS_DIFF_NET;
1316 V_stat_writes(volptr, writeIdx)++;
1317 if (author != AnonymousID) {
1318 V_stat_writes(volptr, writeIdx+1)++;
1322 * Update the volume's authorship information in response to this
1323 * directory operation. Get the current time, decide to which time
1324 * slot this operation belongs, and bump the appropriate slot.
1326 currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1327 timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1328 currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1329 currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1330 currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1331 currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1332 VOL_STATS_TIME_IDX_5);
1333 if (parentptr->disk.author == author) {
1334 V_stat_dirSameAuthor(volptr, timeIdx)++;
1337 V_stat_dirDiffAuthor(volptr, timeIdx)++;
1339 #endif /* FS_STATS_DETAILED */
1341 parentptr->disk.author = author;
1342 parentptr->disk.linkCount = linkcount;
1343 parentptr->disk.unixModifyTime = FT_ApproxTime(); /* This should be set from CLIENT!! */
1344 parentptr->disk.serverModifyTime = FT_ApproxTime();
1345 parentptr->changed_newTime = 1; /* vnode changed, write it back. */
1350 * Update the target file's (or dir's) status block after the specified
1351 * operation is complete. Note that some other fields maybe updated by
1352 * the individual module.
1355 /* XXX INCOMPLETE - More attention is needed here! */
1357 Update_TargetVnodeStatus(Vnode *targetptr,
1359 struct client *client,
1360 AFSStoreStatus *InStatus,
1365 #if FS_STATS_DETAILED
1366 Date currDate; /*Current date*/
1367 int writeIdx; /*Write index to bump*/
1368 int timeIdx; /*Authorship time index to bump*/
1369 #endif /* FS_STATS_DETAILED */
1371 if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR)) { /* initialize new file */
1372 targetptr->disk.parent = parentptr->vnodeNumber;
1373 VN_SET_LEN(targetptr, length);
1374 /* targetptr->disk.group = 0; save some cycles */
1375 targetptr->disk.modeBits = 0777;
1376 targetptr->disk.owner = client->ViceId;
1377 targetptr->disk.dataVersion = 0 ; /* consistent with the client */
1378 targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1379 /* the inode was created in Alloc_NewVnode() */
1382 #if FS_STATS_DETAILED
1384 * Update file write stats for this volume. Note that the auth
1385 * counter is located immediately after its associated ``distance''
1388 if (client->InSameNetwork)
1389 writeIdx = VOL_STATS_SAME_NET;
1391 writeIdx = VOL_STATS_DIFF_NET;
1392 V_stat_writes(volptr, writeIdx)++;
1393 if (client->ViceId != AnonymousID) {
1394 V_stat_writes(volptr, writeIdx+1)++;
1398 * We only count operations that DON'T involve creating new objects
1399 * (files, symlinks, directories) or simply setting status as
1400 * authorship-change operations.
1402 if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1404 * Update the volume's authorship information in response to this
1405 * file operation. Get the current time, decide to which time
1406 * slot this operation belongs, and bump the appropriate slot.
1408 currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1409 timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1410 currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1411 currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1412 currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1413 currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1414 VOL_STATS_TIME_IDX_5);
1415 if (targetptr->disk.author == client->ViceId) {
1416 V_stat_fileSameAuthor(volptr, timeIdx)++;
1418 V_stat_fileDiffAuthor(volptr, timeIdx)++;
1421 #endif /* FS_STATS_DETAILED */
1423 if (!(Caller & TVS_SSTATUS))
1424 targetptr->disk.author = client->ViceId;
1425 if (Caller & TVS_SDATA) {
1426 targetptr->disk.dataVersion++;
1427 if (VanillaUser(client))
1429 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1430 #ifdef CREATE_SGUID_ADMIN_ONLY
1431 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1435 if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1436 /* store status, must explicitly request to change the date */
1437 if (InStatus->Mask & AFS_SETMODTIME)
1438 targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1440 else {/* other: date always changes, but perhaps to what is specified by caller */
1441 targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime());
1443 if (InStatus->Mask & AFS_SETOWNER) {
1444 /* admin is allowed to do chmod, chown as well as chown, chmod. */
1445 if (VanillaUser(client))
1447 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1448 #ifdef CREATE_SGUID_ADMIN_ONLY
1449 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1452 targetptr->disk.owner = InStatus->Owner;
1453 if (VolumeRootVnode (targetptr)) {
1454 Error errorCode = 0; /* what should be done with this? */
1456 V_owner(targetptr->volumePtr) = InStatus->Owner;
1457 VUpdateVolume(&errorCode, targetptr->volumePtr);
1460 if (InStatus->Mask & AFS_SETMODE) {
1461 int modebits = InStatus->UnixModeBits;
1462 #define CREATE_SGUID_ADMIN_ONLY 1
1463 #ifdef CREATE_SGUID_ADMIN_ONLY
1464 if (VanillaUser(client))
1465 modebits = modebits & 0777;
1467 if (VanillaUser(client)) {
1468 targetptr->disk.modeBits = modebits;
1471 targetptr->disk.modeBits = modebits;
1473 case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1474 AUD_INT, CHK_STOREDATA, AUD_END); break;
1476 case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1477 AUD_INT, CHK_STORESTATUS, AUD_END); break;
1482 targetptr->disk.serverModifyTime = FT_ApproxTime();
1483 if (InStatus->Mask & AFS_SETGROUP)
1484 targetptr->disk.group = InStatus->Group;
1485 /* vnode changed : to be written back by VPutVnode */
1486 targetptr->changed_newTime = 1;
1488 } /*Update_TargetVnodeStatus*/
1492 * Fills the CallBack structure with the expiration time and type of callback
1493 * structure. Warning: this function is currently incomplete.
1496 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1498 /* CallBackTime could not be 0 */
1499 if (CallBackTime == 0) {
1500 ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1501 CallBack->ExpirationTime = 0;
1503 CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1504 CallBack->CallBackVersion = CALLBACK_VERSION;
1505 CallBack->CallBackType = CB_SHARED; /* The default for now */
1507 } /*SetCallBackStruct*/
1511 * Adjusts (Subtract) "length" number of blocks from the volume's disk
1512 * allocation; if some error occured (exceeded volume quota or partition
1513 * was full, or whatever), it frees the space back and returns the code.
1514 * We usually pre-adjust the volume space to make sure that there's
1515 * enough space before consuming some.
1518 AdjustDiskUsage(Volume *volptr, afs_size_t length, afs_size_t checkLength)
1523 VAdjustDiskUsage(&rc, volptr, length, checkLength);
1525 VAdjustDiskUsage(&nc, volptr, -length, (afs_size_t) 0);
1526 if (rc == VOVERQUOTA) {
1527 ViceLog(2,("Volume %u (%s) is full\n",
1528 V_id(volptr), V_name(volptr)));
1531 if (rc == VDISKFULL) {
1532 ViceLog(0,("Partition %s that contains volume %u is full\n",
1533 volptr->partition->name, V_id(volptr)));
1536 ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc));
1541 } /*AdjustDiskUsage*/
1544 * Common code that handles the creation of a new file (SAFS_CreateFile and
1545 * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1548 Alloc_NewVnode(Vnode *parentptr,
1553 struct AFSFid *OutFid,
1555 afs_size_t BlocksPreallocatedForVnode)
1557 int errorCode = 0; /* Error code returned back */
1560 Inode nearInode; /* hint for inode allocation in solaris */
1562 if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1563 BlocksPreallocatedForVnode))) {
1564 ViceLog(25, ("Insufficient space to allocate %d blocks\n",
1565 BlocksPreallocatedForVnode));
1569 *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1570 if (errorCode != 0) {
1571 VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode,
1575 OutFid->Volume = V_id(volptr);
1576 OutFid->Vnode = (*targetptr)->vnodeNumber;
1577 OutFid->Unique = (*targetptr)->disk.uniquifier;
1579 nearInode = VN_GET_INO(parentptr); /* parent is also in same vol */
1581 /* create the inode now itself */
1582 inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1583 VPartitionPath(V_partition(volptr)), nearInode,
1584 V_id(volptr), (*targetptr)->vnodeNumber,
1585 (*targetptr)->disk.uniquifier, 1);
1587 /* error in creating inode */
1588 if (!VALID_INO(inode))
1590 ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n",
1591 (*targetptr)->volumePtr->header->diskstuff.id,
1592 (*targetptr)->vnodeNumber,
1594 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,
1596 (*targetptr)->delete = 1; /* delete vnode */
1599 VN_SET_INO(*targetptr, inode);
1600 IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1602 /* copy group from parent dir */
1603 (*targetptr)->disk.group = parentptr->disk.group;
1605 if (parentptr->disk.cloned)
1607 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1608 if ((errorCode = CopyOnWrite(parentptr, volptr))) /* disk full */
1610 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1611 /* delete the vnode previously allocated */
1612 (*targetptr)->delete = 1;
1613 VAdjustDiskUsage(&temp, volptr,
1614 -BlocksPreallocatedForVnode, (afs_size_t) 0);
1615 IH_REALLYCLOSE((*targetptr)->handle);
1616 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) )
1617 ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1618 volptr->partition->name,
1619 PrintInode(NULL, inode)));
1620 IH_RELEASE((*targetptr)->handle);
1626 /* add the name to the directory */
1627 SetDirHandle(dir, parentptr);
1628 if ((errorCode = Create(dir,(char *)Name, OutFid))) {
1629 (*targetptr)->delete = 1;
1630 VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode,
1632 IH_REALLYCLOSE((*targetptr)->handle);
1633 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1634 ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1635 volptr->partition->name,
1636 PrintInode(NULL, inode)));
1637 IH_RELEASE((*targetptr)->handle);
1643 } /*Alloc_NewVnode*/
1647 * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1651 HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType)
1653 int Time; /* Used for time */
1654 int writeVnode = targetptr->changed_oldTime; /* save original status */
1656 /* Does the caller has Lock priviledges; root extends locks, however */
1657 if (LockingType != LockExtend && !(rights & PRSFS_LOCK))
1659 targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
1660 Time = FT_ApproxTime();
1661 switch (LockingType) {
1664 if (Time > targetptr->disk.lock.lockTime)
1665 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0;
1666 Time += AFS_LOCKWAIT;
1667 if (LockingType == LockRead) {
1668 if (targetptr->disk.lock.lockCount >= 0) {
1669 ++(targetptr->disk.lock.lockCount);
1670 targetptr->disk.lock.lockTime = Time;
1671 } else return(EAGAIN);
1673 if (targetptr->disk.lock.lockCount == 0) {
1674 targetptr->disk.lock.lockCount = -1;
1675 targetptr->disk.lock.lockTime = Time;
1676 } else return(EAGAIN);
1680 Time += AFS_LOCKWAIT;
1681 if (targetptr->disk.lock.lockCount != 0)
1682 targetptr->disk.lock.lockTime = Time;
1683 else return(EINVAL);
1686 if ((--targetptr->disk.lock.lockCount) <= 0)
1687 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0;
1690 targetptr->changed_oldTime = writeVnode; /* restore old status */
1691 ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1696 /* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
1699 CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode)
1703 if (!(rights & Prfs_Mode))
1705 if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE)))
1711 * If some flags (i.e. min or max quota) are set, the volume's in disk
1712 * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1713 * update, if applicable.
1716 RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus,
1717 char *Name, char *OfflineMsg, char *Motd)
1719 Error errorCode = 0;
1721 if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1722 V_minquota(volptr) = StoreVolStatus->MinQuota;
1723 if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1724 V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1725 if (strlen(OfflineMsg) > 0) {
1726 strcpy(V_offlineMessage(volptr), OfflineMsg);
1728 if (strlen(Name) > 0) {
1729 strcpy(V_name(volptr), Name);
1731 #if TRANSARC_VOL_STATS
1733 * We don't overwrite the motd field, since it's now being used
1737 if (strlen(Motd) > 0) {
1738 strcpy(V_motd(volptr), Motd);
1740 #endif /* FS_STATS_DETAILED */
1741 VUpdateVolume(&errorCode, volptr);
1744 } /*RXUpdate_VolumeStatus*/
1749 Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus,
1750 struct BBS *Name, struct BBS *OfflineMsg,
1753 Error errorCode = 0;
1755 if (StoreVolStatus->MinQuota > -1)
1756 V_minquota(volptr) = StoreVolStatus->MinQuota;
1757 if (StoreVolStatus->MaxQuota > -1)
1758 V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1759 if (OfflineMsg->SeqLen > 1)
1760 strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody);
1761 if (Name->SeqLen > 1)
1762 strcpy(V_name(volptr), Name->SeqBody);
1763 #if TRANSARC_VOL_STATS
1765 * We don't overwrite the motd field, since it's now being used
1769 if (Motd->SeqLen > 1)
1770 strcpy(V_motd(volptr), Motd->SeqBody);
1771 #endif /* FS_STATS_DETAILED */
1772 VUpdateVolume(&errorCode, volptr);
1775 } /*Update_VolumeStatus*/
1779 * Get internal volume-related statistics from the Volume disk label
1780 * structure and put it into the VolumeStatus structure, status; it's
1781 * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return
1782 * the volume status to the caller.
1785 GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg,
1786 struct BBS *motd, Volume *volptr)
1788 status->Vid = V_id(volptr);
1789 status->ParentId = V_parentId(volptr);
1790 status->Online = V_inUse(volptr);
1791 status->InService = V_inService(volptr);
1792 status->Blessed = V_blessed(volptr);
1793 status->NeedsSalvage = V_needsSalvaged(volptr);
1794 if (VolumeWriteable(volptr))
1795 status->Type = ReadWrite;
1797 status->Type = ReadOnly;
1798 status->MinQuota = V_minquota(volptr);
1799 status->MaxQuota = V_maxquota(volptr);
1800 status->BlocksInUse = V_diskused(volptr);
1801 status->PartBlocksAvail = volptr->partition->free;
1802 status->PartMaxBlocks = volptr->partition->totalUsable;
1803 strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
1804 name->SeqLen = strlen(V_name(volptr)) + 1;
1805 if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
1806 strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
1807 offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
1808 if (offMsg->SeqLen > offMsg->MaxSeqLen)
1809 offMsg->SeqLen = offMsg -> MaxSeqLen;
1811 /*Don't do anything with the motd field*/
1812 strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen);
1813 motd->SeqLen = strlen(nullString) + 1;
1815 if (motd->SeqLen > motd->MaxSeqLen)
1816 motd->SeqLen = motd -> MaxSeqLen;
1818 } /*GetVolumeStatus*/
1821 RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg,
1822 char **motd, Volume *volptr)
1826 status->Vid = V_id(volptr);
1827 status->ParentId = V_parentId(volptr);
1828 status->Online = V_inUse(volptr);
1829 status->InService = V_inService(volptr);
1830 status->Blessed = V_blessed(volptr);
1831 status->NeedsSalvage = V_needsSalvaged(volptr);
1832 if (VolumeWriteable(volptr))
1833 status->Type = ReadWrite;
1835 status->Type = ReadOnly;
1836 status->MinQuota = V_minquota(volptr);
1837 status->MaxQuota = V_maxquota(volptr);
1838 status->BlocksInUse = V_diskused(volptr);
1839 status->PartBlocksAvail = volptr->partition->free;
1840 status->PartMaxBlocks = volptr->partition->totalUsable;
1842 /* now allocate and copy these things; they're freed by the RXGEN stub */
1843 temp = strlen(V_name(volptr)) + 1;
1844 *name = malloc(temp);
1846 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1849 strcpy(*name, V_name(volptr));
1850 temp = strlen(V_offlineMessage(volptr)) + 1;
1851 *offMsg = malloc(temp);
1853 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1856 strcpy(*offMsg, V_offlineMessage(volptr));
1857 #if TRANSARC_VOL_STATS
1860 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1863 strcpy(*motd, nullString);
1865 temp = strlen(V_motd(volptr)) + 1;
1866 *motd = malloc(temp);
1868 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1871 strcpy(*motd, V_motd(volptr));
1872 #endif /* FS_STATS_DETAILED */
1874 } /*RXGetVolumeStatus*/
1878 FileNameOK(register char *aname)
1880 register afs_int32 i, tc;
1883 /* watch for @sys on the right */
1884 if (strcmp(aname+i-4, "@sys") == 0) return 0;
1886 while ((tc = *aname++)) {
1887 if (tc == '/') return 0; /* very bad character to encounter */
1889 return 1; /* file name is ok */
1894 /* Debugging tool to print Volume Statu's contents */
1896 PrintVolumeStatus(VolumeStatus *status)
1898 ViceLog(5,("Volume header contains:\n"));
1899 ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1900 status->Vid, status->ParentId, status->Online, status->InService,
1901 status->Blessed, status->NeedsSalvage));
1902 ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1903 ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1904 status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1906 } /*PrintVolumeStatus*/
1910 * This variant of symlink is expressly to support the AFS/DFS translator
1911 * and is not supported by the AFS fileserver. We just return EINVAL.
1912 * The cache manager should not generate this call to an AFS cache manager.
1914 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1915 struct AFSFid *DirFid,
1918 struct AFSStoreStatus *InStatus,
1919 struct AFSFid *OutFid,
1920 struct AFSFetchStatus *OutFidStatus,
1921 struct AFSFetchStatus *OutDirStatus,
1922 struct AFSCallBack *CallBack,
1923 struct AFSVolSync *Sync)
1928 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1929 struct ResidencyCmdInputs *Inputs,
1930 struct ResidencyCmdOutputs *Outputs)
1935 static struct afs_buffer {
1936 struct afs_buffer *next;
1937 } *freeBufferList = 0;
1938 static int afs_buffersAlloced = 0;
1940 static FreeSendBuffer(register struct afs_buffer *adata)
1943 afs_buffersAlloced--;
1944 adata->next = freeBufferList;
1945 freeBufferList = adata;
1949 } /*FreeSendBuffer*/
1951 /* allocate space for sender */
1952 static char *AllocSendBuffer()
1954 register struct afs_buffer *tp;
1957 afs_buffersAlloced++;
1958 if (!freeBufferList) {
1962 tmp = malloc(sendBufSize);
1964 ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1969 tp = freeBufferList;
1970 freeBufferList = tp->next;
1974 } /*AllocSendBuffer*/
1977 * This routine returns the status info associated with the targetptr vnode
1978 * in the AFSFetchStatus structure. Some of the newer fields, such as
1979 * SegSize and Group are not yet implemented
1982 void GetStatus(Vnode *targetptr,
1983 AFSFetchStatus *status,
1985 afs_int32 anyrights,
1988 /* initialize return status from a vnode */
1989 status->InterfaceVersion = 1;
1990 status->SyncCounter = status->dataVersionHigh = status->lockCount =
1991 status->errorCode = 0;
1992 status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1993 if (targetptr->disk.type == vFile)
1994 status->FileType = File;
1995 else if (targetptr->disk.type == vDirectory)
1996 status->FileType = Directory;
1997 else if (targetptr->disk.type == vSymlink)
1998 status->FileType = SymbolicLink;
2000 status->FileType = Invalid; /*invalid type field */
2001 status->LinkCount = targetptr->disk.linkCount;
2002 SET_STATUS_LEN(status, targetptr);
2003 status->DataVersion = targetptr->disk.dataVersion;
2004 status->Author = targetptr->disk.author;
2005 status->Owner = targetptr->disk.owner;
2006 status->CallerAccess = rights;
2007 status->AnonymousAccess = anyrights;
2008 status->UnixModeBits = targetptr->disk.modeBits;
2009 status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */
2010 status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2011 status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2012 status->ServerModTime = targetptr->disk.serverModifyTime;
2013 status->Group = targetptr->disk.group;
2014 status->lockCount = targetptr->disk.lock.lockCount;
2015 status->errorCode = 0;
2020 afs_int32 common_FetchData64 (struct rx_call *acall,
2024 struct AFSFetchStatus *OutStatus,
2025 struct AFSCallBack *CallBack,
2026 struct AFSVolSync *Sync,
2029 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2030 Vnode * parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */
2031 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2032 int errorCode = 0; /* return code to caller */
2033 int fileCode = 0; /* return code from vol package */
2034 Volume * volptr = 0; /* pointer to the volume */
2035 struct client *client; /* pointer to the client data */
2036 struct rx_connection *tcon; /* the connection we're part of */
2037 afs_int32 rights, anyrights; /* rights for this and any user */
2038 struct client *t_client; /* tmp ptr to client data */
2039 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2040 #if FS_STATS_DETAILED
2041 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2042 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2043 struct timeval opStartTime,
2044 opStopTime; /* Start/stop times for RPC op*/
2045 struct timeval xferStartTime,
2046 xferStopTime; /* Start/stop times for xfer portion*/
2047 struct timeval elapsedTime; /* Transfer time */
2048 afs_size_t bytesToXfer; /* # bytes to xfer*/
2049 afs_size_t bytesXferred; /* # bytes actually xferred*/
2050 int readIdx; /* Index of read stats array to bump*/
2051 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2054 * Set our stats pointers, remember when the RPC operation started, and
2055 * tally the operation.
2057 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2058 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2062 TM_GetTimeOfDay(&opStartTime, 0);
2063 #endif /* FS_STATS_DETAILED */
2065 ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2066 Fid->Volume, Fid->Vnode, Fid->Unique));
2068 AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2071 if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2074 /* Get ptr to client data for user Id for logging */
2075 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2076 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2077 ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2078 Fid->Volume, Fid->Vnode, Fid->Unique,
2079 inet_ntoa(logHostAddr), t_client->ViceId));
2081 * Get volume/vnode for the fetched file; caller's access rights to
2082 * it are also returned
2084 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2085 DONTCHECK, &parentwhentargetnotdir,
2086 &client, READ_LOCK, &rights, &anyrights)))
2089 SetVolumeSync(Sync, volptr);
2091 #if FS_STATS_DETAILED
2093 * Remember that another read operation was performed.
2096 if (client->InSameNetwork)
2097 readIdx = VOL_STATS_SAME_NET;
2099 readIdx = VOL_STATS_DIFF_NET;
2100 V_stat_reads(volptr, readIdx)++;
2101 if (client->ViceId != AnonymousID) {
2102 V_stat_reads(volptr, readIdx+1)++;
2105 #endif /* FS_STATS_DETAILED */
2107 /* Check whether the caller has permission access to fetch the data */
2108 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2113 * Drop the read lock on the parent directory after saving the parent
2114 * vnode information we need to pass to GetStatus
2116 if (parentwhentargetnotdir != NULL) {
2117 tparentwhentargetnotdir = *parentwhentargetnotdir;
2118 VPutVnode(&fileCode, parentwhentargetnotdir);
2119 assert(!fileCode || (fileCode == VSALVAGE));
2120 parentwhentargetnotdir = NULL;
2123 #if FS_STATS_DETAILED
2125 * Remember when the data transfer started.
2127 TM_GetTimeOfDay(&xferStartTime, 0);
2128 #endif /* FS_STATS_DETAILED */
2130 /* actually do the data transfer */
2131 #if FS_STATS_DETAILED
2132 errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2133 (afs_size_t) Pos, (afs_size_t) Len, type,
2134 &bytesToXfer, &bytesXferred);
2136 if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2137 (afs_size_t) Pos, (afs_size_t) Len,
2140 #endif /* FS_STATS_DETAILED */
2142 #if FS_STATS_DETAILED
2144 * At this point, the data transfer is done, for good or ill. Remember
2145 * when the transfer ended, bump the number of successes/failures, and
2146 * integrate the transfer size and elapsed time into the stats. If the
2147 * operation failed, we jump to the appropriate point.
2149 TM_GetTimeOfDay(&xferStopTime, 0);
2151 (xferP->numXfers)++;
2153 (xferP->numSuccesses)++;
2156 * Bump the xfer sum by the number of bytes actually sent, NOT the
2159 tot_bytesXferred += bytesXferred;
2160 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2161 tot_bytesXferred &= 0x3FF;
2162 if (bytesXferred < xferP->minBytes)
2163 xferP->minBytes = bytesXferred;
2164 if (bytesXferred > xferP->maxBytes)
2165 xferP->maxBytes = bytesXferred;
2168 * Tally the size of the object. Note: we tally the actual size,
2169 * NOT the number of bytes that made it out over the wire.
2171 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2172 (xferP->count[0])++;
2174 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2175 (xferP->count[1])++;
2177 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2178 (xferP->count[2])++;
2180 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2181 (xferP->count[3])++;
2183 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2184 (xferP->count[4])++;
2186 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2187 (xferP->count[5])++;
2189 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2190 (xferP->count[6])++;
2192 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2193 (xferP->count[7])++;
2195 (xferP->count[8])++;
2197 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2198 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2199 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2200 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2201 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2203 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2204 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2209 * Finally, go off to tell our caller the bad news in case the
2214 #endif /* FS_STATS_DETAILED */
2216 /* write back the OutStatus from the target vnode */
2217 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2219 /* if a r/w volume, promise a callback to the caller */
2220 if (VolumeWriteable(volptr))
2221 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2223 struct AFSFid myFid;
2224 memset(&myFid, 0, sizeof(struct AFSFid));
2225 myFid.Volume = Fid->Volume;
2226 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2230 /* Update and store volume/vnode and parent vnodes back */
2231 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2232 ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2233 CallPostamble(tcon);
2235 #if FS_STATS_DETAILED
2236 TM_GetTimeOfDay(&opStopTime, 0);
2237 if (errorCode == 0) {
2239 (opP->numSuccesses)++;
2240 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2241 fs_stats_AddTo((opP->sumTime), elapsedTime);
2242 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2243 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2244 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2246 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2247 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2252 #endif /* FS_STATS_DETAILED */
2254 osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2257 } /*common_FetchData64*/
2259 afs_int32 SRXAFS_FetchData (struct rx_call *acall,
2263 struct AFSFetchStatus *OutStatus,
2264 struct AFSCallBack *CallBack,
2265 struct AFSVolSync *Sync)
2270 code = common_FetchData64 (acall, Fid,
2271 (afs_size_t) Pos, (afs_size_t) Len,
2277 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall,
2281 struct AFSFetchStatus *OutStatus,
2282 struct AFSCallBack *CallBack,
2283 struct AFSVolSync *Sync)
2286 afs_size_t tPos, tLen;
2288 #ifdef AFS_64BIT_ENV
2289 #ifndef AFS_LARGEFILE_ENV
2290 if (Pos + Len > 0x7fffffff)
2292 #endif /* !AFS_LARGEFILE_ENV */
2295 #else /* AFS_64BIT_ENV */
2296 if (Pos.high || Len.high)
2300 #endif /* AFS_64BIT_ENV */
2302 code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2307 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,
2309 struct AFSOpaque *AccessList,
2310 struct AFSFetchStatus *OutStatus,
2311 struct AFSVolSync *Sync)
2313 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2314 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2315 int errorCode = 0; /* return error code to caller */
2316 Volume * volptr = 0; /* pointer to the volume */
2317 struct client *client; /* pointer to the client data */
2318 afs_int32 rights, anyrights; /* rights for this and any user */
2319 struct rx_connection *tcon = rx_ConnectionOf(acall);
2320 struct client *t_client; /* tmp ptr to client data */
2321 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2322 #if FS_STATS_DETAILED
2323 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2324 struct timeval opStartTime,
2325 opStopTime; /* Start/stop times for RPC op*/
2326 struct timeval elapsedTime; /* Transfer time */
2329 * Set our stats pointer, remember when the RPC operation started, and
2330 * tally the operation.
2332 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2336 TM_GetTimeOfDay(&opStartTime, 0);
2337 #endif /* FS_STATS_DETAILED */
2339 ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2340 Fid->Volume, Fid->Vnode, Fid->Unique));
2342 AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2344 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2347 /* Get ptr to client data for user Id for logging */
2348 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2349 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2350 ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2351 Fid->Volume, Fid->Vnode, Fid->Unique,
2352 inet_ntoa(logHostAddr), t_client->ViceId));
2354 AccessList->AFSOpaque_len = 0;
2355 AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2356 if (!AccessList->AFSOpaque_val) {
2357 ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2362 * Get volume/vnode for the fetched file; caller's access rights to it
2365 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2366 DONTCHECK, &parentwhentargetnotdir,
2367 &client, READ_LOCK, &rights, &anyrights)))
2370 SetVolumeSync(Sync, volptr);
2372 /* Check whether we have permission to fetch the ACL */
2373 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2377 /* Get the Access List from the dir's vnode */
2378 if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2382 /* Get OutStatus back From the target Vnode */
2383 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2386 /* Update and store volume/vnode and parent vnodes back */
2387 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2388 ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2389 errorCode, AccessList->AFSOpaque_val));
2390 CallPostamble(tcon);
2392 #if FS_STATS_DETAILED
2393 TM_GetTimeOfDay(&opStopTime, 0);
2394 if (errorCode == 0) {
2396 (opP->numSuccesses)++;
2397 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2398 fs_stats_AddTo((opP->sumTime), elapsedTime);
2399 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2400 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2401 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2403 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2404 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2409 #endif /* FS_STATS_DETAILED */
2411 osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2413 } /*SRXAFS_FetchACL*/
2417 * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2418 * merged into it when possible.
2421 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2423 struct AFSFetchStatus *OutStatus,
2424 struct AFSCallBack *CallBack,
2425 struct AFSVolSync *Sync)
2427 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2428 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2429 int errorCode = 0; /* return code to caller */
2430 Volume * volptr = 0; /* pointer to the volume */
2431 struct client *client; /* pointer to the client data */
2432 afs_int32 rights, anyrights; /* rights for this and any user */
2433 struct client *t_client; /* tmp ptr to client data */
2434 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2435 struct rx_connection *tcon = rx_ConnectionOf(acall);
2437 /* Get ptr to client data for user Id for logging */
2438 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2439 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2440 ViceLog(1, ("SAFS_FetchStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
2441 Fid->Volume, Fid->Vnode, Fid->Unique,
2442 inet_ntoa(logHostAddr), t_client->ViceId));
2444 AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2447 * Get volume/vnode for the fetched file; caller's rights to it are
2450 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2451 DONTCHECK, &parentwhentargetnotdir,
2452 &client, READ_LOCK, &rights, &anyrights)))
2453 goto Bad_FetchStatus;
2455 /* set volume synchronization information */
2456 SetVolumeSync(Sync, volptr);
2458 /* Are we allowed to fetch Fid's status? */
2459 if (targetptr->disk.type != vDirectory) {
2460 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2461 CHK_FETCHSTATUS, 0))) {
2462 if (rx_GetCallAbortCode(acall) == errorCode)
2463 rx_SetCallAbortCode(acall, 0);
2464 goto Bad_FetchStatus;
2468 /* set OutStatus From the Fid */
2469 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2471 /* If a r/w volume, also set the CallBack state */
2472 if (VolumeWriteable(volptr))
2473 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2475 struct AFSFid myFid;
2476 memset(&myFid, 0, sizeof(struct AFSFid));
2477 myFid.Volume = Fid->Volume;
2478 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2482 /* Update and store volume/vnode and parent vnodes back */
2483 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2484 ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2487 } /*SAFSS_FetchStatus*/
2490 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2491 struct AFSCBFids *Fids,
2492 struct AFSBulkStats *OutStats,
2493 struct AFSCBs *CallBacks,
2494 struct AFSVolSync *Sync)
2498 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2499 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2500 int errorCode = 0; /* return code to caller */
2501 Volume * volptr = 0; /* pointer to the volume */
2502 struct client *client; /* pointer to the client data */
2503 afs_int32 rights, anyrights; /* rights for this and any user */
2504 register struct AFSFid *tfid; /* file id we're dealing with now */
2505 struct rx_connection *tcon = rx_ConnectionOf(acall);
2506 #if FS_STATS_DETAILED
2507 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2508 struct timeval opStartTime,
2509 opStopTime; /* Start/stop times for RPC op*/
2510 struct timeval elapsedTime; /* Transfer time */
2513 * Set our stats pointer, remember when the RPC operation started, and
2514 * tally the operation.
2516 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2520 TM_GetTimeOfDay(&opStartTime, 0);
2521 #endif /* FS_STATS_DETAILED */
2523 ViceLog(1, ("SAFS_BulkStatus\n"));
2525 AFSCallStats.TotalCalls++;
2528 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2529 if (nfiles <= 0) { /* Sanity check */
2531 goto Audit_and_Return;
2534 /* allocate space for return output parameters */
2535 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2536 malloc(nfiles * sizeof(struct AFSFetchStatus));
2537 if (!OutStats->AFSBulkStats_val) {
2538 ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2541 OutStats->AFSBulkStats_len = nfiles;
2542 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2543 malloc(nfiles * sizeof(struct AFSCallBack));
2544 if (!CallBacks->AFSCBs_val) {
2545 ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2548 CallBacks->AFSCBs_len = nfiles;
2550 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2551 goto Bad_BulkStatus;
2553 tfid = Fids->AFSCBFids_val;
2554 for (i=0; i<nfiles; i++, tfid++) {
2556 * Get volume/vnode for the fetched file; caller's rights to it
2560 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2561 DONTCHECK, &parentwhentargetnotdir, &client,
2562 READ_LOCK, &rights, &anyrights)))
2563 goto Bad_BulkStatus;
2564 /* set volume synchronization information, but only once per call */
2566 SetVolumeSync(Sync, volptr);
2568 /* Are we allowed to fetch Fid's status? */
2569 if (targetptr->disk.type != vDirectory) {
2570 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2571 CHK_FETCHSTATUS, 0))) {
2572 if (rx_GetCallAbortCode(acall) == errorCode)
2573 rx_SetCallAbortCode(acall, 0);
2574 goto Bad_BulkStatus;
2578 /* set OutStatus From the Fid */
2579 GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2580 rights, anyrights, parentwhentargetnotdir);
2582 /* If a r/w volume, also set the CallBack state */
2583 if (VolumeWriteable(volptr))
2584 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2585 &CallBacks->AFSCBs_val[i]);
2587 struct AFSFid myFid;
2588 memset(&myFid, 0, sizeof(struct AFSFid));
2589 myFid.Volume = tfid->Volume;
2590 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2591 &CallBacks->AFSCBs_val[i]);
2594 /* put back the file ID and volume */
2595 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2596 parentwhentargetnotdir = (Vnode *) 0;
2597 targetptr = (Vnode *) 0;
2598 volptr = (Volume *) 0;
2602 /* Update and store volume/vnode and parent vnodes back */
2603 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2604 CallPostamble(tcon);
2606 #if FS_STATS_DETAILED
2607 TM_GetTimeOfDay(&opStopTime, 0);
2608 if (errorCode == 0) {
2610 (opP->numSuccesses)++;
2611 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2612 fs_stats_AddTo((opP->sumTime), elapsedTime);
2613 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2614 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2615 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2617 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2618 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2623 #endif /* FS_STATS_DETAILED */
2626 ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode));
2627 osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2630 } /*SRXAFS_BulkStatus*/
2633 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2634 struct AFSCBFids *Fids,
2635 struct AFSBulkStats *OutStats,
2636 struct AFSCBs *CallBacks,
2637 struct AFSVolSync *Sync)
2641 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2642 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2643 int errorCode = 0; /* return code to caller */
2644 Volume * volptr = 0; /* pointer to the volume */
2645 struct client *client; /* pointer to the client data */
2646 afs_int32 rights, anyrights; /* rights for this and any user */
2647 register struct AFSFid *tfid; /* file id we're dealing with now */
2648 struct rx_connection *tcon;
2649 AFSFetchStatus *tstatus;
2650 #if FS_STATS_DETAILED
2651 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2652 struct timeval opStartTime,
2653 opStopTime; /* Start/stop times for RPC op*/
2654 struct timeval elapsedTime; /* Transfer time */
2657 * Set our stats pointer, remember when the RPC operation started, and
2658 * tally the operation.
2660 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2664 TM_GetTimeOfDay(&opStartTime, 0);
2665 #endif /* FS_STATS_DETAILED */
2667 ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2669 AFSCallStats.TotalCalls++;
2672 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2673 if (nfiles <= 0) { /* Sanity check */
2675 goto Audit_and_Return;
2678 /* allocate space for return output parameters */
2679 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2680 malloc(nfiles * sizeof(struct AFSFetchStatus));
2681 if (!OutStats->AFSBulkStats_val) {
2682 ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2685 OutStats->AFSBulkStats_len = nfiles;
2686 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2687 malloc(nfiles * sizeof(struct AFSCallBack));
2688 if (!CallBacks->AFSCBs_val) {
2689 ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2692 CallBacks->AFSCBs_len = nfiles;
2694 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2695 goto Bad_InlineBulkStatus;
2698 tfid = Fids->AFSCBFids_val;
2699 for (i=0; i<nfiles; i++, tfid++) {
2701 * Get volume/vnode for the fetched file; caller's rights to it
2705 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2706 DONTCHECK, &parentwhentargetnotdir, &client,
2707 READ_LOCK, &rights, &anyrights))) {
2708 tstatus = &OutStats->AFSBulkStats_val[i];
2709 tstatus->errorCode = errorCode;
2710 parentwhentargetnotdir = (Vnode *) 0;
2711 targetptr = (Vnode *) 0;
2712 volptr = (Volume *) 0;
2716 /* set volume synchronization information, but only once per call */
2718 SetVolumeSync(Sync, volptr);
2720 /* Are we allowed to fetch Fid's status? */
2721 if (targetptr->disk.type != vDirectory) {
2722 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2723 CHK_FETCHSTATUS, 0))) {
2724 tstatus = &OutStats->AFSBulkStats_val[i];
2725 tstatus->errorCode = errorCode;
2726 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2727 parentwhentargetnotdir = (Vnode *) 0;
2728 targetptr = (Vnode *) 0;
2729 volptr = (Volume *) 0;
2734 /* set OutStatus From the Fid */
2735 GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i],
2736 rights, anyrights, parentwhentargetnotdir);
2738 /* If a r/w volume, also set the CallBack state */
2739 if (VolumeWriteable(volptr))
2740 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2741 &CallBacks->AFSCBs_val[i]);
2743 struct AFSFid myFid;
2744 memset(&myFid, 0, sizeof(struct AFSFid));
2745 myFid.Volume = tfid->Volume;
2746 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2747 &CallBacks->AFSCBs_val[i]);
2750 /* put back the file ID and volume */
2751 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2752 parentwhentargetnotdir = (Vnode *) 0;
2753 targetptr = (Vnode *) 0;
2754 volptr = (Volume *) 0;
2757 Bad_InlineBulkStatus:
2758 /* Update and store volume/vnode and parent vnodes back */
2759 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2760 CallPostamble(tcon);
2762 #if FS_STATS_DETAILED
2763 TM_GetTimeOfDay(&opStopTime, 0);
2764 if (errorCode == 0) {
2766 (opP->numSuccesses)++;
2767 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2768 fs_stats_AddTo((opP->sumTime), elapsedTime);
2769 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2770 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2771 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2773 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2774 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2779 #endif /* FS_STATS_DETAILED */
2782 ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode));
2783 osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2786 } /*SRXAFS_InlineBulkStatus*/
2789 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,
2791 struct AFSFetchStatus *OutStatus,
2792 struct AFSCallBack *CallBack,
2793 struct AFSVolSync *Sync)
2796 struct rx_connection *tcon;
2797 #if FS_STATS_DETAILED
2798 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2799 struct timeval opStartTime,
2800 opStopTime; /* Start/stop times for RPC op*/
2801 struct timeval elapsedTime; /* Transfer time */
2804 * Set our stats pointer, remember when the RPC operation started, and
2805 * tally the operation.
2807 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2811 TM_GetTimeOfDay(&opStartTime, 0);
2812 #endif /* FS_STATS_DETAILED */
2814 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2815 goto Bad_FetchStatus;
2817 code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2820 CallPostamble(tcon);
2822 #if FS_STATS_DETAILED
2823 TM_GetTimeOfDay(&opStopTime, 0);
2826 (opP->numSuccesses)++;
2827 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2828 fs_stats_AddTo((opP->sumTime), elapsedTime);
2829 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2830 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2831 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2833 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2834 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2839 #endif /* FS_STATS_DETAILED */
2841 osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2844 } /*SRXAFS_FetchStatus*/
2847 afs_int32 common_StoreData64 (struct rx_call *acall,
2849 struct AFSStoreStatus *InStatus,
2852 afs_offs_t FileLength,
2853 struct AFSFetchStatus *OutStatus,
2854 struct AFSVolSync *Sync)
2856 Vnode * targetptr = 0; /* pointer to input fid */
2857 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2858 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2859 int errorCode = 0; /* return code for caller */
2860 int fileCode = 0; /* return code from vol package */
2861 Volume * volptr = 0; /* pointer to the volume header */
2862 struct client * client; /* pointer to client structure */
2863 afs_int32 rights, anyrights; /* rights for this and any user */
2864 struct client *t_client; /* tmp ptr to client data */
2865 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2866 struct rx_connection *tcon;
2867 #if FS_STATS_DETAILED
2868 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2869 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2870 struct timeval opStartTime,
2871 opStopTime; /* Start/stop times for RPC op*/
2872 struct timeval xferStartTime,
2873 xferStopTime; /* Start/stop times for xfer portion*/
2874 struct timeval elapsedTime; /* Transfer time */
2875 afs_size_t bytesToXfer; /* # bytes to xfer */
2876 afs_size_t bytesXferred; /* # bytes actually xfer */
2877 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2880 * Set our stats pointers, remember when the RPC operation started, and
2881 * tally the operation.
2883 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2884 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2889 ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2890 Fid->Volume, Fid->Vnode, Fid->Unique));
2891 TM_GetTimeOfDay(&opStartTime, 0);
2892 #endif /* FS_STATS_DETAILED */
2895 AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2898 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2901 /* Get ptr to client data for user Id for logging */
2902 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2903 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2904 ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2905 Fid->Volume, Fid->Vnode, Fid->Unique,
2906 inet_ntoa(logHostAddr), t_client->ViceId));
2907 #ifdef AFS_LARGEFILE_ENV
2908 ViceLog(25, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d, Pos (0X%x,0X%x), Len (0X%x,0X%x), FileLen (0X%x,0X%x)\n",
2909 Fid->Volume, Fid->Vnode, Fid->Unique,
2910 inet_ntoa(logHostAddr), t_client->ViceId,
2911 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
2912 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff),
2913 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff)));
2914 #else /* !AFS_LARGEFILE_ENV */
2915 ViceLog(25, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d, Pos 0X%x, Len 0X%x, FileLen 0X%x\n",
2916 Fid->Volume, Fid->Vnode, Fid->Unique,
2917 inet_ntoa(logHostAddr), t_client->ViceId,
2921 #endif /* !AFS_LARGEFILE_ENV */
2925 * Get associated volume/vnode for the stored file; caller's rights
2928 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2929 MustNOTBeDIR, &parentwhentargetnotdir,
2930 &client, WRITE_LOCK, &rights, &anyrights))) {
2934 /* set volume synchronization information */
2935 SetVolumeSync(Sync, volptr);
2937 if ((targetptr->disk.type == vSymlink)) {
2938 /* Should we return a better error code here??? */
2943 /* Check if we're allowed to store the data */
2944 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2945 CHK_STOREDATA, InStatus))) {
2950 * Drop the read lock on the parent directory after saving the parent
2951 * vnode information we need to pass to GetStatus
2953 if (parentwhentargetnotdir != NULL) {
2954 tparentwhentargetnotdir = *parentwhentargetnotdir;
2955 VPutVnode(&fileCode, parentwhentargetnotdir);
2956 assert(!fileCode || (fileCode == VSALVAGE));
2957 parentwhentargetnotdir = NULL;
2962 #if FS_STATS_DETAILED
2964 * Remember when the data transfer started.
2966 TM_GetTimeOfDay(&xferStartTime, 0);
2967 #endif /* FS_STATS_DETAILED */
2969 /* Do the actual storing of the data */
2970 #if FS_STATS_DETAILED
2971 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2972 (afs_size_t) Pos, (afs_size_t) Length,
2973 (afs_size_t) FileLength,
2974 (InStatus->Mask & AFS_FSYNC),
2975 &bytesToXfer, &bytesXferred);
2977 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2979 (afs_size_t) Pos, (afs_size_t) Length,
2980 (afs_size_t) FileLength,
2981 (InStatus->Mask & AFS_FSYNC));
2982 if (errorCode && (!targetptr->changed_newTime))
2984 #endif /* FS_STATS_DETAILED */
2985 #if FS_STATS_DETAILED
2987 * At this point, the data transfer is done, for good or ill. Remember
2988 * when the transfer ended, bump the number of successes/failures, and
2989 * integrate the transfer size and elapsed time into the stats. If the
2990 * operation failed, we jump to the appropriate point.
2992 TM_GetTimeOfDay(&xferStopTime, 0);
2994 (xferP->numXfers)++;
2996 (xferP->numSuccesses)++;
2999 * Bump the xfer sum by the number of bytes actually sent, NOT the
3002 tot_bytesXferred += bytesXferred;
3003 (xferP->sumBytes) += (tot_bytesXferred >> 10);
3004 tot_bytesXferred &= 0x3FF;
3005 if (bytesXferred < xferP->minBytes)
3006 xferP->minBytes = bytesXferred;
3007 if (bytesXferred > xferP->maxBytes)
3008 xferP->maxBytes = bytesXferred;
3011 * Tally the size of the object. Note: we tally the actual size,
3012 * NOT the number of bytes that made it out over the wire.
3014 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3015 (xferP->count[0])++;
3017 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3018 (xferP->count[1])++;
3020 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3021 (xferP->count[2])++;
3023 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3024 (xferP->count[3])++;
3026 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3027 (xferP->count[4])++;
3029 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3030 (xferP->count[5])++;
3032 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3033 (xferP->count[6])++;
3035 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3036 (xferP->count[7])++;
3038 (xferP->count[8])++;
3040 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3041 fs_stats_AddTo((xferP->sumTime), elapsedTime);
3042 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3043 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3044 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3046 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3047 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3053 * Finally, go off to tell our caller the bad news in case the
3056 if (errorCode && (!targetptr->changed_newTime))
3058 #endif /* FS_STATS_DETAILED */
3060 /* Update the status of the target's vnode */
3061 Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
3062 volptr, (afs_size_t) 0);
3064 /* Get the updated File's status back to the caller */
3065 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
3068 /* Update and store volume/vnode and parent vnodes back */
3069 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3070 ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3072 CallPostamble(tcon);
3074 #if FS_STATS_DETAILED
3075 TM_GetTimeOfDay(&opStopTime, 0);
3076 if (errorCode == 0) {
3078 (opP->numSuccesses)++;
3079 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3080 fs_stats_AddTo((opP->sumTime), elapsedTime);
3081 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3082 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3083 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3085 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3086 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3090 #endif /* FS_STATS_DETAILED */
3092 osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
3095 } /*common_StoreData64*/
3097 afs_int32 SRXAFS_StoreData (struct rx_call *acall,
3099 struct AFSStoreStatus *InStatus,
3102 afs_uint32 FileLength,
3103 struct AFSFetchStatus *OutStatus,
3104 struct AFSVolSync *Sync)
3108 code = common_StoreData64 (acall, Fid, InStatus, Pos, Length, FileLength,
3112 } /*SRXAFS_StoreData*/
3114 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,
3116 struct AFSStoreStatus *InStatus,
3119 afs_uint64 FileLength,
3120 struct AFSFetchStatus *OutStatus,
3121 struct AFSVolSync *Sync)
3126 afs_offs_t tFileLength;
3128 #ifdef AFS_64BIT_ENV
3129 #ifndef AFS_LARGEFILE_ENV
3130 if (FileLength > 0x7fffffff)
3132 #endif /* !AFS_LARGEFILE_ENV */
3135 tFileLength = FileLength;
3136 #else /* AFS_64BIT_ENV */
3137 if (FileLength.high)
3140 tLength = Length.low;
3141 tFileLength = FileLength.low;
3142 #endif /* AFS_64BIT_ENV */
3144 code = common_StoreData64 (acall, Fid, InStatus, tPos, tLength, tFileLength,
3149 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,
3151 struct AFSOpaque *AccessList,
3152 struct AFSFetchStatus *OutStatus,
3153 struct AFSVolSync *Sync)
3155 Vnode * targetptr = 0; /* pointer to input fid */
3156 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3157 int errorCode = 0; /* return code for caller */
3158 struct AFSStoreStatus InStatus; /* Input status for fid */
3159 Volume * volptr = 0; /* pointer to the volume header */
3160 struct client * client; /* pointer to client structure */
3161 afs_int32 rights, anyrights; /* rights for this and any user */
3162 struct rx_connection *tcon;
3163 struct client *t_client; /* tmp ptr to client data */
3164 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3165 #if FS_STATS_DETAILED
3166 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3167 struct timeval opStartTime,
3168 opStopTime; /* Start/stop times for RPC op*/
3169 struct timeval elapsedTime; /* Transfer time */
3172 * Set our stats pointer, remember when the RPC operation started, and
3173 * tally the operation.
3175 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3179 TM_GetTimeOfDay(&opStartTime, 0);
3180 #endif /* FS_STATS_DETAILED */
3181 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3184 /* Get ptr to client data for user Id for logging */
3185 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3186 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3187 ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3188 Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3189 inet_ntoa(logHostAddr), t_client->ViceId));
3191 AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3194 InStatus.Mask = 0; /* not storing any status */
3197 * Get associated volume/vnode for the target dir; caller's rights
3198 * are also returned.
3200 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3201 MustBeDIR, &parentwhentargetnotdir,
3202 &client, WRITE_LOCK, &rights, &anyrights))) {
3206 /* set volume synchronization information */
3207 SetVolumeSync(Sync, volptr);
3209 /* Check if we have permission to change the dir's ACL */
3210 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3211 CHK_STOREACL, &InStatus))) {
3215 /* Build and store the new Access List for the dir */
3216 if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3220 targetptr->changed_newTime = 1; /* status change of directory */
3222 /* convert the write lock to a read lock before breaking callbacks */
3223 VVnodeWriteToRead(&errorCode, targetptr);
3224 assert(!errorCode || errorCode == VSALVAGE);
3226 /* break call backs on the directory */
3227 BreakCallBack(client->host, Fid, 0);
3229 /* Get the updated dir's status back to the caller */
3230 GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3233 /* Update and store volume/vnode and parent vnodes back */
3234 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3235 ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3236 CallPostamble(tcon);
3238 #if FS_STATS_DETAILED
3239 TM_GetTimeOfDay(&opStopTime, 0);
3240 if (errorCode == 0) {
3242 (opP->numSuccesses)++;
3243 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3244 fs_stats_AddTo((opP->sumTime), elapsedTime);
3245 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3246 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3247 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3249 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3250 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3254 #endif /* FS_STATS_DETAILED */
3256 osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3259 } /*SRXAFS_StoreACL*/
3263 * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3264 * should be merged when possible.
3267 SAFSS_StoreStatus (struct rx_call *acall,
3269 struct AFSStoreStatus *InStatus,
3270 struct AFSFetchStatus *OutStatus,
3271 struct AFSVolSync *Sync)
3274 Vnode * targetptr = 0; /* pointer to input fid */
3275 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3276 int errorCode = 0; /* return code for caller */
3277 Volume * volptr = 0; /* pointer to the volume header */
3278 struct client * client; /* pointer to client structure */
3279 afs_int32 rights, anyrights; /* rights for this and any user */
3280 struct client *t_client; /* tmp ptr to client data */
3281 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3282 struct rx_connection *tcon = rx_ConnectionOf(acall);
3284 /* Get ptr to client data for user Id for logging */
3285 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3286 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3287 ViceLog(1, ("SAFS_StoreStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
3288 Fid->Volume, Fid->Vnode, Fid->Unique,
3289 inet_ntoa(logHostAddr), t_client->ViceId));
3291 AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3294 * Get volume/vnode for the target file; caller's rights to it are
3297 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3298 DONTCHECK, &parentwhentargetnotdir,
3299 &client, WRITE_LOCK, &rights, &anyrights))) {
3300 goto Bad_StoreStatus;
3303 /* set volume synchronization information */
3304 SetVolumeSync(Sync, volptr);
3306 /* Check if the caller has proper permissions to store status to Fid */
3307 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3308 CHK_STORESTATUS, InStatus))) {
3309 goto Bad_StoreStatus;
3312 * Check for a symbolic link; we can't chmod these (otherwise could
3313 * change a symlink to a mt pt or vice versa)
3315 if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3317 goto Bad_StoreStatus;
3320 /* Update the status of the target's vnode */
3321 Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3322 (parentwhentargetnotdir ?
3323 parentwhentargetnotdir : targetptr), volptr,
3326 /* convert the write lock to a read lock before breaking callbacks */
3327 VVnodeWriteToRead(&errorCode, targetptr);
3328 assert(!errorCode || errorCode == VSALVAGE);
3330 /* Break call backs on Fid */
3331 BreakCallBack(client->host, Fid, 0);
3333 /* Return the updated status back to caller */
3334 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3337 /* Update and store volume/vnode and parent vnodes back */
3338 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3339 ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3342 } /*SAFSS_StoreStatus*/
3345 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,
3347 struct AFSStoreStatus *InStatus,
3348 struct AFSFetchStatus *OutStatus,
3349 struct AFSVolSync *Sync)
3352 struct rx_connection *tcon;
3353 #if FS_STATS_DETAILED
3354 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3355 struct timeval opStartTime,
3356 opStopTime; /* Start/stop times for RPC op*/
3357 struct timeval elapsedTime; /* Transfer time */
3360 * Set our stats pointer, remember when the RPC operation started, and
3361 * tally the operation.
3363 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3367 TM_GetTimeOfDay(&opStartTime, 0);
3368 #endif /* FS_STATS_DETAILED */
3370 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3371 goto Bad_StoreStatus;
3373 code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3376 CallPostamble(tcon);
3378 #if FS_STATS_DETAILED
3379 TM_GetTimeOfDay(&opStopTime, 0);
3382 (opP->numSuccesses)++;
3383 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3384 fs_stats_AddTo((opP->sumTime), elapsedTime);
3385 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3386 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3387 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3389 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3390 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3395 #endif /* FS_STATS_DETAILED */
3397 osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3400 } /*SRXAFS_StoreStatus*/
3404 * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3405 * merged in when possible.
3408 SAFSS_RemoveFile (struct rx_call *acall,
3409 struct AFSFid *DirFid,
3411 struct AFSFetchStatus *OutDirStatus,
3412 struct AFSVolSync *Sync)
3414 Vnode * parentptr = 0; /* vnode of input Directory */
3415 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3416 Vnode * targetptr = 0; /* file to be deleted */
3417 Volume * volptr = 0; /* pointer to the volume header */
3418 AFSFid fileFid; /* area for Fid from the directory */
3419 int errorCode = 0; /* error code */
3420 DirHandle dir; /* Handle for dir package I/O */
3421 struct client * client; /* pointer to client structure */
3422 afs_int32 rights, anyrights; /* rights for this and any user */
3423 struct client *t_client; /* tmp ptr to client data */
3424 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3425 struct rx_connection *tcon = rx_ConnectionOf(acall);
3428 /* Get ptr to client data for user Id for logging */
3429 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3430 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3431 ViceLog(1, ("SAFS_RemoveFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3432 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3433 inet_ntoa(logHostAddr), t_client->ViceId));
3435 AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3438 * Get volume/vnode for the parent dir; caller's access rights are
3441 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3442 MustBeDIR, &parentwhentargetnotdir,
3443 &client, WRITE_LOCK, &rights, &anyrights))) {
3444 goto Bad_RemoveFile;
3446 /* set volume synchronization information */
3447 SetVolumeSync(Sync, volptr);
3449 /* Does the caller has delete (& write) access to the parent directory? */
3450 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3451 goto Bad_RemoveFile;
3454 /* Actually delete the desired file */
3455 if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3456 &fileFid, Name, MustNOTBeDIR))) {
3457 goto Bad_RemoveFile;
3460 /* Update the vnode status of the parent dir */
3461 #if FS_STATS_DETAILED
3462 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3463 parentptr->disk.linkCount, client->InSameNetwork);
3465 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3466 parentptr->disk.linkCount);
3467 #endif /* FS_STATS_DETAILED */
3469 /* Return the updated parent dir's status back to caller */
3470 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3472 /* Handle internal callback state for the parent and the deleted file */
3473 if (targetptr->disk.linkCount == 0) {
3474 /* no references left, discard entry */
3475 DeleteFileCallBacks(&fileFid);
3476 /* convert the parent lock to a read lock before breaking callbacks */
3477 VVnodeWriteToRead(&errorCode, parentptr);
3478 assert(!errorCode || errorCode == VSALVAGE);
3480 /* convert the parent lock to a read lock before breaking callbacks */
3481 VVnodeWriteToRead(&errorCode, parentptr);
3482 assert(!errorCode || errorCode == VSALVAGE);
3483 /* convert the target lock to a read lock before breaking callbacks */
3484 VVnodeWriteToRead(&errorCode, targetptr);
3485 assert(!errorCode || errorCode == VSALVAGE);
3486 /* tell all the file has changed */
3487 BreakCallBack(client->host, &fileFid, 1);
3490 /* break call back on the directory */
3491 BreakCallBack(client->host, DirFid, 0);
3494 /* Update and store volume/vnode and parent vnodes back */
3495 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3497 ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode));
3500 } /*SAFSS_RemoveFile*/
3503 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3504 struct AFSFid *DirFid,
3506 struct AFSFetchStatus *OutDirStatus,
3507 struct AFSVolSync *Sync)
3510 struct rx_connection *tcon;
3511 #if FS_STATS_DETAILED
3512 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3513 struct timeval opStartTime,
3514 opStopTime; /* Start/stop times for RPC op*/
3515 struct timeval elapsedTime; /* Transfer time */
3518 * Set our stats pointer, remember when the RPC operation started, and
3519 * tally the operation.
3521 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3525 TM_GetTimeOfDay(&opStartTime, 0);
3526 #endif /* FS_STATS_DETAILED */
3528 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3529 goto Bad_RemoveFile;
3531 code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3534 CallPostamble(tcon);
3536 #if FS_STATS_DETAILED
3537 TM_GetTimeOfDay(&opStopTime, 0);
3540 (opP->numSuccesses)++;
3541 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3542 fs_stats_AddTo((opP->sumTime), elapsedTime);
3543 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3544 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3545 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3547 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3548 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3553 #endif /* FS_STATS_DETAILED */
3555 osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3558 } /*SRXAFS_RemoveFile*/
3562 * This routine is called exclusively from SRXAFS_CreateFile(), and should
3563 * be merged in when possible.
3566 SAFSS_CreateFile (struct rx_call *acall,
3567 struct AFSFid *DirFid,
3569 struct AFSStoreStatus *InStatus,
3570 struct AFSFid *OutFid,
3571 struct AFSFetchStatus *OutFidStatus,
3572 struct AFSFetchStatus *OutDirStatus,
3573 struct AFSCallBack *CallBack,
3574 struct AFSVolSync *Sync)
3576 Vnode * parentptr = 0; /* vnode of input Directory */
3577 Vnode * targetptr = 0; /* vnode of the new file */
3578 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3579 Volume * volptr = 0; /* pointer to the volume header */
3580 int errorCode = 0; /* error code */
3581 DirHandle dir; /* Handle for dir package I/O */
3582 struct client * client; /* pointer to client structure */
3583 afs_int32 rights, anyrights; /* rights for this and any user */
3584 struct client *t_client; /* tmp ptr to client data */
3585 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3586 struct rx_connection *tcon = rx_ConnectionOf(acall);
3590 /* Get ptr to client data for user Id for logging */
3591 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3592 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3593 ViceLog(1, ("SAFS_CreateFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3594 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3595 inet_ntoa(logHostAddr), t_client->ViceId));
3597 AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3599 if (!FileNameOK(Name)) {
3601 goto Bad_CreateFile;
3605 * Get associated volume/vnode for the parent dir; caller long are
3608 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3609 MustBeDIR, &parentwhentargetnotdir,
3610 &client, WRITE_LOCK, &rights, &anyrights))) {
3611 goto Bad_CreateFile;
3614 /* set volume synchronization information */
3615 SetVolumeSync(Sync, volptr);
3617 /* Can we write (and insert) onto the parent directory? */
3618 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3619 goto Bad_CreateFile;
3621 /* get a new vnode for the file to be created and set it up */
3622 if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3623 Name, OutFid, vFile, nBlocks(0)))) {
3624 goto Bad_CreateFile;
3627 /* update the status of the parent vnode */
3628 #if FS_STATS_DETAILED
3629 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3630 parentptr->disk.linkCount, client->InSameNetwork);
3632 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3633 parentptr->disk.linkCount);
3634 #endif /* FS_STATS_DETAILED */
3636 /* update the status of the new file's vnode */
3637 Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3638 parentptr, volptr, (afs_size_t)0);
3640 /* set up the return status for the parent dir and the newly created file */
3641 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3642 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3644 /* convert the write lock to a read lock before breaking callbacks */
3645 VVnodeWriteToRead(&errorCode, parentptr);
3646 assert(!errorCode || errorCode == VSALVAGE);
3648 /* break call back on parent dir */
3649 BreakCallBack(client->host, DirFid, 0);
3651 /* Return a callback promise for the newly created file to the caller */
3652 SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3655 /* Update and store volume/vnode and parent vnodes back */
3656 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3658 ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode));
3661 } /*SAFSS_CreateFile*/
3664 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3665 struct AFSFid *DirFid,
3667 struct AFSStoreStatus *InStatus,
3668 struct AFSFid *OutFid,
3669 struct AFSFetchStatus *OutFidStatus,
3670 struct AFSFetchStatus *OutDirStatus,
3671 struct AFSCallBack *CallBack,
3672 struct AFSVolSync *Sync)
3675 struct rx_connection *tcon;
3676 #if FS_STATS_DETAILED
3677 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3678 struct timeval opStartTime,
3679 opStopTime; /* Start/stop times for RPC op*/
3680 struct timeval elapsedTime; /* Transfer time */
3683 * Set our stats pointer, remember when the RPC operation started, and
3684 * tally the operation.
3686 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3690 TM_GetTimeOfDay(&opStartTime, 0);
3691 #endif /* FS_STATS_DETAILED */
3693 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3694 goto Bad_CreateFile;
3696 code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3697 OutFidStatus, OutDirStatus, CallBack, Sync);
3700 CallPostamble(tcon);
3702 #if FS_STATS_DETAILED
3703 TM_GetTimeOfDay(&opStopTime, 0);
3706 (opP->numSuccesses)++;
3707 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3708 fs_stats_AddTo((opP->sumTime), elapsedTime);
3709 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3710 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3711 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3713 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3714 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3718 #endif /* FS_STATS_DETAILED */
3720 osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3723 } /*SRXAFS_CreateFile*/
3727 * This routine is called exclusively from SRXAFS_Rename(), and should be
3728 * merged in when possible.
3731 SAFSS_Rename (struct rx_call *acall,
3732 struct AFSFid *OldDirFid,
3734 struct AFSFid *NewDirFid,
3736 struct AFSFetchStatus *OutOldDirStatus,
3737 struct AFSFetchStatus *OutNewDirStatus,
3738 struct AFSVolSync *Sync)
3740 Vnode * oldvptr = 0; /* vnode of the old Directory */
3741 Vnode * newvptr = 0; /* vnode of the new Directory */
3742 Vnode * fileptr = 0; /* vnode of the file to move */
3743 Vnode * newfileptr = 0; /* vnode of the file to delete */
3744 Vnode * testvptr = 0; /* used in directory tree walk */
3745 Vnode * parent = 0; /* parent for use in SetAccessList */
3746 int errorCode = 0; /* error code */
3747 int fileCode = 0; /* used when writing Vnodes */
3748 VnodeId testnode; /* used in directory tree walk */
3749 AFSFid fileFid; /* Fid of file to move */
3750 AFSFid newFileFid; /* Fid of new file */
3751 DirHandle olddir; /* Handle for dir package I/O */
3752 DirHandle newdir; /* Handle for dir package I/O */
3753 DirHandle filedir; /* Handle for dir package I/O */
3754 DirHandle newfiledir; /* Handle for dir package I/O */
3755 Volume * volptr = 0; /* pointer to the volume header */
3756 struct client * client; /* pointer to client structure */
3757 afs_int32 rights, anyrights; /* rights for this and any user */
3758 afs_int32 newrights; /* rights for this user */
3759 afs_int32 newanyrights; /* rights for any user */
3760 int doDelete; /* deleted the rename target (ref count now 0) */
3762 struct client *t_client; /* tmp ptr to client data */
3763 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3764 struct rx_connection *tcon = rx_ConnectionOf(acall);
3769 FidZero(&newfiledir);
3771 /* Get ptr to client data for user Id for logging */
3772 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3773 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3774 ViceLog(1, ("SAFS_Rename %s to %s, Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3775 OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3776 OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3778 inet_ntoa(logHostAddr), t_client->ViceId));
3780 AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3782 if (!FileNameOK(NewName)) {
3786 if (OldDirFid->Volume != NewDirFid->Volume) {
3791 if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3792 (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) ||
3793 (strlen(NewName) == 0) || (strlen(OldName) == 0) ) {
3799 if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3800 if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3801 &oldvptr, MustBeDIR, &parent,
3802 &client, WRITE_LOCK, &rights,
3807 if (OldDirFid->Vnode == NewDirFid->Vnode) {
3809 newrights = rights, newanyrights = anyrights;
3812 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3813 &newvptr, MustBeDIR, &parent,
3814 &client, WRITE_LOCK, &newrights,
3821 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3822 &newvptr, MustBeDIR, &parent,
3823 &client, WRITE_LOCK, &newrights,
3828 if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3829 MustBeDIR, &parent, &client, WRITE_LOCK,
3830 &rights, &anyrights))) {
3836 /* set volume synchronization information */
3837 SetVolumeSync(Sync, volptr);
3839 if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3842 if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3846 /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3847 * call to CopyOnWrite returns error, it is not necessary to revert back
3848 * the effects of the first call because the contents of the volume is
3849 * not modified, it is only replicated.
3851 if (oldvptr->disk.cloned)
3853 ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n"));
3854 if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3857 SetDirHandle(&olddir, oldvptr);
3858 if (newvptr->disk.cloned)
3860 ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n"));
3861 if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3865 SetDirHandle(&newdir, newvptr);
3867 /* Lookup the file to delete its vnode */
3868 if (Lookup(&olddir, OldName, &fileFid)) {
3872 if (fileFid.Vnode == oldvptr->vnodeNumber ||
3873 fileFid.Vnode == newvptr->vnodeNumber) {
3874 errorCode = FSERR_ELOOP;
3877 fileFid.Volume = V_id(volptr);
3878 fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3879 if (errorCode != 0) {
3880 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3881 VTakeOffline (volptr);
3884 if (fileptr->disk.uniquifier != fileFid.Unique) {
3885 ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3886 VTakeOffline (volptr);
3891 if (fileptr->disk.type != vDirectory &&
3892 oldvptr != newvptr &&
3893 fileptr->disk.linkCount != 1) {
3895 * Hard links exist to this file - cannot move one of the links to
3896 * a new directory because of AFS restrictions (this is the same
3897 * reason that links cannot be made across directories, i.e.
3904 /* Lookup the new file */
3905 if (!(Lookup(&newdir, NewName, &newFileFid))) {
3906 if (readonlyServer) {
3907 errorCode = VREADONLY;
3910 if (!(newrights & PRSFS_DELETE)) {
3914 if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3915 newFileFid.Vnode == newvptr->vnodeNumber ||
3916 newFileFid.Vnode == fileFid.Vnode) {
3920 newFileFid.Volume = V_id(volptr);
3921 newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3922 if (errorCode != 0) {
3923 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3924 VTakeOffline (volptr);
3927 if (fileptr->disk.uniquifier != fileFid.Unique) {
3928 ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3929 VTakeOffline (volptr);
3933 SetDirHandle(&newfiledir, newfileptr);
3934 /* Now check that we're moving directories over directories properly, etc.
3935 * return proper POSIX error codes:
3936 * if fileptr is a file and new is a dir: EISDIR.
3937 * if fileptr is a dir and new is a file: ENOTDIR.
3938 * Also, dir to be removed must be empty, of course.
3940 if (newfileptr->disk.type == vDirectory) {
3941 if (fileptr->disk.type != vDirectory) {
3945 if ((IsEmpty(&newfiledir))) {
3951 if (fileptr->disk.type == vDirectory) {
3952 errorCode = ENOTDIR;
3959 * ok - now we check that the old name is not above new name in the
3960 * directory structure. This is to prevent removing a subtree alltogether
3962 if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3963 for (testnode = newvptr->disk.parent; testnode != 0;) {
3964 if (testnode == oldvptr->vnodeNumber) {
3965 testnode = oldvptr->disk.parent;
3968 if ((testnode == fileptr->vnodeNumber) ||
3969 (testnode == newvptr->vnodeNumber)) {
3970 errorCode = FSERR_ELOOP;
3973 if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3974 errorCode = FSERR_ELOOP;
3977 testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3978 assert(errorCode == 0);
3979 testnode = testvptr->disk.parent;
3980 VPutVnode(&errorCode, testvptr);
3981 assert(errorCode == 0);
3984 /* Do the CopyonWrite first before modifying anything else. Copying is
3985 * required because we may have to change entries for ..
3987 if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3989 ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n"));
3990 if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3994 /* If the new name exists already, delete it and the file it points to */
3997 /* Delete NewName from its directory */
3998 code = Delete(&newdir, NewName);
4001 /* Drop the link count */
4002 newfileptr->disk.linkCount--;
4003 if (newfileptr->disk.linkCount == 0) { /* Link count 0 - delete */
4005 VN_GET_LEN(newSize, newfileptr);
4006 VAdjustDiskUsage(&errorCode, volptr,
4007 -nBlocks(newSize), (afs_size_t) 0);
4008 if (VN_GET_INO(newfileptr)) {
4009 IH_REALLYCLOSE(newfileptr->handle);
4010 errorCode = IH_DEC(V_linkHandle(volptr),
4011 VN_GET_INO(newfileptr),
4012 V_parentId(volptr));
4013 IH_RELEASE(newfileptr->handle);
4014 if (errorCode == -1) {
4015 ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
4016 PrintInode(NULL, VN_GET_INO(newfileptr)),
4018 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
4019 ViceLog(0, ("Do we need to fsck?"));
4022 VN_SET_INO(newfileptr, (Inode)0);
4023 newfileptr->delete = 1; /* Mark NewName vnode to delete */
4026 /* Link count did not drop to zero.
4027 * Mark NewName vnode as changed - updates stime.
4029 newfileptr->changed_newTime = 1;
4034 * If the create below fails, and the delete above worked, we have
4035 * removed the new name and not replaced it. This is not very likely,
4036 * but possible. We could try to put the old file back, but it is
4037 * highly unlikely that it would work since it would involve issuing
4040 if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
4043 /* Delete the old name */
4044 assert(Delete(&olddir,(char *) OldName) == 0);
4046 /* if the directory length changes, reflect it in the statistics */
4047 #if FS_STATS_DETAILED
4048 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4049 oldvptr->disk.linkCount, client->InSameNetwork);
4050 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4051 newvptr->disk.linkCount, client->InSameNetwork);
4053 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4054 oldvptr->disk.linkCount);
4055 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4056 newvptr->disk.linkCount);
4057 #endif /* FS_STATS_DETAILED */
4059 if (oldvptr == newvptr)
4060 oldvptr->disk.dataVersion--; /* Since it was bumped by 2! */
4062 fileptr->disk.parent = newvptr->vnodeNumber;
4063 fileptr->changed_newTime = 1; /* status change of moved file */
4065 /* if we are dealing with a rename of a directory */
4066 if (fileptr->disk.type == vDirectory) {
4067 assert(!fileptr->disk.cloned);
4068 SetDirHandle(&filedir, fileptr);
4069 /* fix .. to point to the correct place */
4070 Delete(&filedir, ".."); /* No assert--some directories may be bad */
4071 assert(Create(&filedir, "..", NewDirFid) == 0);
4072 fileptr->disk.dataVersion++;
4073 /* if the parent directories are different the link counts have to be */
4074 /* changed due to .. in the renamed directory */
4075 if (oldvptr != newvptr) {
4076 oldvptr->disk.linkCount--;
4077 newvptr->disk.linkCount++;
4081 /* set up return status */
4082 GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
4083 GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
4084 if (newfileptr && doDelete) {
4085 DeleteFileCallBacks(&newFileFid); /* no other references */
4090 /* convert the write locks to a read locks before breaking callbacks */
4091 VVnodeWriteToRead(&errorCode, newvptr);
4092 assert(!errorCode || errorCode == VSALVAGE);
4093 if (oldvptr != newvptr) {
4094 VVnodeWriteToRead(&errorCode, oldvptr);
4095 assert(!errorCode || errorCode == VSALVAGE);
4097 if (newfileptr && !doDelete) {
4098 /* convert the write lock to a read lock before breaking callbacks */
4099 VVnodeWriteToRead(&errorCode, newfileptr);
4100 assert(!errorCode || errorCode == VSALVAGE);
4103 /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */
4104 BreakCallBack(client->host, NewDirFid, 0);
4105 if (oldvptr != newvptr) {
4106 BreakCallBack(client->host, OldDirFid, 0);
4107 if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
4108 BreakCallBack(client->host, &fileFid, 0);
4111 /* Note: it is not necessary to break the callback */
4113 DeleteFileCallBacks(&newFileFid); /* no other references */
4115 /* other's still exist (with wrong link count) */
4116 BreakCallBack(client->host, &newFileFid, 1);
4121 VPutVnode(&fileCode, newfileptr);
4122 assert(fileCode == 0);
4124 PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
4129 FidZap(&newfiledir);
4130 ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4136 afs_int32 SRXAFS_Rename (struct rx_call *acall,
4137 struct AFSFid *OldDirFid,
4139 struct AFSFid *NewDirFid,
4141 struct AFSFetchStatus *OutOldDirStatus,
4142 struct AFSFetchStatus *OutNewDirStatus,
4143 struct AFSVolSync *Sync)
4146 struct rx_connection *tcon;
4147 #if FS_STATS_DETAILED
4148 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4149 struct timeval opStartTime,
4150 opStopTime; /* Start/stop times for RPC op*/
4151 struct timeval elapsedTime; /* Transfer time */
4154 * Set our stats pointer, remember when the RPC operation started, and
4155 * tally the operation.
4157 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4161 TM_GetTimeOfDay(&opStartTime, 0);
4162 #endif /* FS_STATS_DETAILED */
4164 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4167 code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4168 OutOldDirStatus, OutNewDirStatus, Sync);
4171 CallPostamble(tcon);
4173 #if FS_STATS_DETAILED
4174 TM_GetTimeOfDay(&opStopTime, 0);
4177 (opP->numSuccesses)++;
4178 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4179 fs_stats_AddTo((opP->sumTime), elapsedTime);
4180 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4181 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4182 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4184 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4185 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4190 #endif /* FS_STATS_DETAILED */
4192 osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
4199 * This routine is called exclusively by SRXAFS_Symlink(), and should be
4200 * merged into it when possible.
4203 SAFSS_Symlink (struct rx_call *acall,
4204 struct AFSFid *DirFid,
4207 struct AFSStoreStatus *InStatus,
4208 struct AFSFid *OutFid,
4209 struct AFSFetchStatus *OutFidStatus,
4210 struct AFSFetchStatus *OutDirStatus,
4211 struct AFSVolSync *Sync)
4214 Vnode * parentptr = 0; /* vnode of input Directory */
4215 Vnode * targetptr = 0; /* vnode of the new link */
4216 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4217 int errorCode = 0; /* error code */
4219 DirHandle dir; /* Handle for dir package I/O */
4220 Volume * volptr = 0; /* pointer to the volume header */
4221 struct client * client; /* pointer to client structure */
4222 afs_int32 rights, anyrights, fd; /* rights for this and any user */
4223 struct client *t_client; /* tmp ptr to client data */
4224 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4226 struct rx_connection *tcon = rx_ConnectionOf(acall);
4230 /* Get ptr to client data for user Id for logging */
4231 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4232 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4233 ViceLog(1, ("SAFS_Symlink %s to %s, Did = %u.%d.%d, Host %s, Id %d\n", Name,
4234 LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4235 inet_ntoa(logHostAddr), t_client->ViceId));
4237 AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
4239 if (!FileNameOK(Name)) {
4245 * Get the vnode and volume for the parent dir along with the caller's
4248 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4249 MustBeDIR, &parentwhentargetnotdir,
4250 &client, WRITE_LOCK, &rights, &anyrights))) {
4254 /* set volume synchronization information */
4255 SetVolumeSync(Sync, volptr);
4257 /* Does the caller has insert (and write) access to the parent directory? */
4258 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4263 * If we're creating a mount point (any x bits clear), we must have
4264 * administer access to the directory, too. Always allow sysadmins
4267 if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
4268 if (readonlyServer) {
4269 errorCode = VREADONLY;
4273 * We have a mountpoint, 'cause we're trying to set the Unix mode
4274 * bits to something with some x bits missing (default mode bits
4275 * if AFS_SETMODE is false is 0777)
4277 if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
4283 /* get a new vnode for the symlink and set it up */
4284 if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
4285 Name, OutFid, vSymlink,
4286 nBlocks(strlen((char *) LinkContents))))) {
4290 /* update the status of the parent vnode */
4291 #if FS_STATS_DETAILED
4292 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4293 parentptr->disk.linkCount, client->InSameNetwork);
4295 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4296 parentptr->disk.linkCount);
4297 #endif /* FS_STATS_DETAILED */
4299 /* update the status of the new symbolic link file vnode */
4300 Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
4301 volptr, (afs_size_t)strlen((char *)LinkContents));
4303 /* Write the contents of the symbolic link name into the target inode */
4304 fdP = IH_OPEN(targetptr->handle);
4305 assert(fdP != NULL);
4306 assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
4309 * Set up and return modified status for the parent dir and new symlink
4312 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4313 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4315 /* convert the write lock to a read lock before breaking callbacks */
4316 VVnodeWriteToRead(&errorCode, parentptr);
4317 assert(!errorCode || errorCode == VSALVAGE);
4319 /* break call back on the parent dir */
4320 BreakCallBack(client->host, DirFid, 0);
4323 /* Write the all modified vnodes (parent, new files) and volume back */
4324 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4326 ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
4332 afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
4333 struct AFSVolSync *Sync;
4334 struct rx_call *acall; /* Rx call */
4335 struct AFSFid *DirFid; /* Parent dir's fid */
4336 char *Name; /* File name to create */
4337 char *LinkContents; /* Contents of the new created file */
4338 struct AFSStoreStatus *InStatus; /* Input status for the new symbolic link */
4339 struct AFSFid *OutFid; /* Fid for newly created symbolic link */
4340 struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
4341 struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
4345 struct rx_connection *tcon;
4346 #if FS_STATS_DETAILED
4347 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4348 struct timeval opStartTime,
4349 opStopTime; /* Start/stop times for RPC op*/
4350 struct timeval elapsedTime; /* Transfer time */
4353 * Set our stats pointer, remember when the RPC operation started, and
4354 * tally the operation.
4356 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
4360 TM_GetTimeOfDay(&opStartTime, 0);
4361 #endif /* FS_STATS_DETAILED */
4363 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4366 code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
4367 OutFidStatus, OutDirStatus, Sync);
4370 CallPostamble(tcon);
4372 #if FS_STATS_DETAILED
4373 TM_GetTimeOfDay(&opStopTime, 0);
4376 (opP->numSuccesses)++;
4377 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4378 fs_stats_AddTo((opP->sumTime), elapsedTime);
4379 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4380 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4381 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4383 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4384 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4389 #endif /* FS_STATS_DETAILED */
4391 osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4394 } /*SRXAFS_Symlink*/
4398 * This routine is called exclusively by SRXAFS_Link(), and should be
4399 * merged into it when possible.
4402 SAFSS_Link (struct rx_call *acall,
4403 struct AFSFid *DirFid,
4405 struct AFSFid *ExistingFid,
4406 struct AFSFetchStatus *OutFidStatus,
4407 struct AFSFetchStatus *OutDirStatus,
4408 struct AFSVolSync *Sync)
4410 Vnode * parentptr = 0; /* vnode of input Directory */
4411 Vnode * targetptr = 0; /* vnode of the new file */
4412 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4413 Volume * volptr = 0; /* pointer to the volume header */
4414 int errorCode = 0; /* error code */
4415 DirHandle dir; /* Handle for dir package I/O */
4416 struct client * client; /* pointer to client structure */
4417 afs_int32 rights, anyrights; /* rights for this and any user */
4418 struct client *t_client; /* tmp ptr to client data */
4419 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4420 struct rx_connection *tcon = rx_ConnectionOf(acall);
4424 /* Get ptr to client data for user Id for logging */
4425 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4426 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4427 ViceLog(1, ("SAFS_Link %s, Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
4428 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4429 ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
4430 inet_ntoa(logHostAddr), t_client->ViceId));
4432 AFSCallStats.Link++, AFSCallStats.TotalCalls++;
4434 if (DirFid->Volume != ExistingFid->Volume) {
4438 if (!FileNameOK(Name)) {
4444 * Get the vnode and volume for the parent dir along with the caller's
4447 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4448 MustBeDIR, &parentwhentargetnotdir,
4449 &client, WRITE_LOCK, &rights, &anyrights))) {
4453 /* set volume synchronization information */
4454 SetVolumeSync(Sync, volptr);
4456 /* Can the caller insert into the parent directory? */
4457 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4461 if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
4462 (DirFid->Vnode == ExistingFid->Vnode)) { /* at present, */
4463 /* AFS fileservers always have directory vnodes that are odd. */
4468 /* get the file vnode */
4469 if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
4472 if (targetptr->disk.type != vFile) {
4476 if (targetptr->disk.parent != DirFid->Vnode) {
4480 if (parentptr->disk.cloned)
4482 ViceLog(25, ("Link : calling CopyOnWrite on target dir\n"));
4483 if ( ( errorCode = CopyOnWrite(parentptr, volptr)))
4484 goto Bad_Link; /* disk full error */
4487 /* add the name to the directory */
4488 SetDirHandle(&dir, parentptr);
4489 if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
4493 /* update the status in the parent vnode */
4494 /**WARNING** --> disk.author SHOULDN'T be modified???? */
4495 #if FS_STATS_DETAILED
4496 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4497 parentptr->disk.linkCount, client->InSameNetwork);
4499 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4500 parentptr->disk.linkCount);
4501 #endif /* FS_STATS_DETAILED */
4503 targetptr->disk.linkCount++;
4504 targetptr->disk.author = client->ViceId;
4505 targetptr->changed_newTime = 1; /* Status change of linked-to file */
4507 /* set up return status */
4508 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4509 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4511 /* convert the write locks to read locks before breaking callbacks */
4512 VVnodeWriteToRead(&errorCode, targetptr);
4513 assert(!errorCode || errorCode == VSALVAGE);
4514 VVnodeWriteToRead(&errorCode, parentptr);
4515 assert(!errorCode || errorCode == VSALVAGE);
4517 /* break call back on DirFid */
4518 BreakCallBack(client->host, DirFid, 0);
4520 * We also need to break the callback for the file that is hard-linked since part
4521 * of its status (like linkcount) is changed
4523 BreakCallBack(client->host, ExistingFid, 0);
4526 /* Write the all modified vnodes (parent, new files) and volume back */
4527 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4529 ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
4535 afs_int32 SRXAFS_Link (struct rx_call *acall,
4536 struct AFSFid *DirFid,
4538 struct AFSFid *ExistingFid,
4539 struct AFSFetchStatus *OutFidStatus,
4540 struct AFSFetchStatus *OutDirStatus,
4541 struct AFSVolSync *Sync)
4544 struct rx_connection *tcon;
4545 #if FS_STATS_DETAILED
4546 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4547 struct timeval opStartTime,
4548 opStopTime; /* Start/stop times for RPC op*/
4549 struct timeval elapsedTime; /* Transfer time */
4552 * Set our stats pointer, remember when the RPC operation started, and
4553 * tally the operation.
4555 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
4559 TM_GetTimeOfDay(&opStartTime, 0);
4560 #endif /* FS_STATS_DETAILED */
4562 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4565 code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
4566 OutDirStatus, Sync);
4569 CallPostamble(tcon);
4571 #if FS_STATS_DETAILED
4572 TM_GetTimeOfDay(&opStopTime, 0);
4575 (opP->numSuccesses)++;
4576 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4577 fs_stats_AddTo((opP->sumTime), elapsedTime);
4578 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4579 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4580 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4582 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4583 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4588 #endif /* FS_STATS_DETAILED */
4590 osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
4597 * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4598 * merged into it when possible.
4601 SAFSS_MakeDir (struct rx_call *acall,
4602 struct AFSFid *DirFid,
4604 struct AFSStoreStatus *InStatus,
4605 struct AFSFid *OutFid,
4606 struct AFSFetchStatus *OutFidStatus,
4607 struct AFSFetchStatus *OutDirStatus,
4608 struct AFSCallBack *CallBack,
4609 struct AFSVolSync *Sync)
4612 Vnode * parentptr = 0; /* vnode of input Directory */
4613 Vnode * targetptr = 0; /* vnode of the new file */
4614 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4615 Volume * volptr = 0; /* pointer to the volume header */
4616 int errorCode = 0; /* error code */
4617 struct acl_accessList * newACL; /* Access list */
4618 int newACLSize; /* Size of access list */
4619 DirHandle dir; /* Handle for dir package I/O */
4620 DirHandle parentdir; /* Handle for dir package I/O */
4621 struct client * client; /* pointer to client structure */
4622 afs_int32 rights, anyrights; /* rights for this and any user */
4623 struct client *t_client; /* tmp ptr to client data */
4624 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4625 struct rx_connection *tcon = rx_ConnectionOf(acall);
4628 FidZero(&parentdir);
4630 /* Get ptr to client data for user Id for logging */
4631 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4632 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4633 ViceLog(1, ("SAFS_MakeDir %s, Did = %u.%d.%d, Host %s, Id %d\n",
4634 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4635 inet_ntoa(logHostAddr), t_client->ViceId));
4637 AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;
4639 if (!FileNameOK(Name)) {
4645 * Get the vnode and volume for the parent dir along with the caller's
4648 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4649 MustBeDIR, &parentwhentargetnotdir,
4650 &client, WRITE_LOCK, &rights, &anyrights))) {
4654 /* set volume synchronization information */
4655 SetVolumeSync(Sync, volptr);
4657 /* Write access to the parent directory? */
4658 #ifdef DIRCREATE_NEED_WRITE
4660 * requires w access for the user to create a directory. this
4661 * closes a loophole in the current security arrangement, since a
4662 * user with i access only can create a directory and get the
4663 * implcit a access that goes with dir ownership, and proceed to
4664 * subvert quota in the volume.
4666 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
4667 (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
4669 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4670 #endif /* DIRCREATE_NEED_WRITE */
4674 #define EMPTYDIRBLOCKS 2
4675 /* get a new vnode and set it up */
4676 if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
4677 Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) {
4681 /* Update the status for the parent dir */
4682 #if FS_STATS_DETAILED
4683 Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4684 parentptr->disk.linkCount+1, client->InSameNetwork);
4686 Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4687 parentptr->disk.linkCount+1);
4688 #endif /* FS_STATS_DETAILED */
4690 /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4691 assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
4692 &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
4693 assert(parentwhentargetnotdir == 0);
4694 memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
4696 /* update the status for the target vnode */
4697 Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
4698 parentptr, volptr, (afs_size_t)0);
4700 /* Actually create the New directory in the directory package */
4701 SetDirHandle(&dir, targetptr);
4702 assert(!(MakeDir(&dir, OutFid, DirFid)));
4704 VN_SET_LEN(targetptr, (afs_size_t) Length(&dir));
4706 /* set up return status */
4707 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4708 GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4710 /* convert the write lock to a read lock before breaking callbacks */
4711 VVnodeWriteToRead(&errorCode, parentptr);
4712 assert(!errorCode || errorCode == VSALVAGE);
4714 /* break call back on DirFid */
4715 BreakCallBack(client->host, DirFid, 0);
4717 /* Return a callback promise to caller */
4718 SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
4721 /* Write the all modified vnodes (parent, new files) and volume back */
4722 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4725 ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode));
4731 afs_int32 SRXAFS_MakeDir (struct rx_call *acall,
4732 struct AFSFid *DirFid,
4734 struct AFSStoreStatus *InStatus,
4735 struct AFSFid *OutFid,
4736 struct AFSFetchStatus *OutFidStatus,
4737 struct AFSFetchStatus *OutDirStatus,
4738 struct AFSCallBack *CallBack,
4739 struct AFSVolSync *Sync)
4742 struct rx_connection *tcon;
4743 #if FS_STATS_DETAILED
4744 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4745 struct timeval opStartTime,
4746 opStopTime; /* Start/stop times for RPC op*/
4747 struct timeval elapsedTime; /* Transfer time */
4750 * Set our stats pointer, remember when the RPC operation started, and
4751 * tally the operation.
4753 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
4757 TM_GetTimeOfDay(&opStartTime, 0);
4758 #endif /* FS_STATS_DETAILED */
4759 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4762 code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
4763 OutFidStatus, OutDirStatus, CallBack, Sync);
4766 CallPostamble(tcon);
4768 #if FS_STATS_DETAILED
4769 TM_GetTimeOfDay(&opStopTime, 0);
4772 (opP->numSuccesses)++;
4773 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4774 fs_stats_AddTo((opP->sumTime), elapsedTime);
4775 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4776 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4777 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4779 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4780 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4785 #endif /* FS_STATS_DETAILED */
4787 osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4790 } /*SRXAFS_MakeDir*/
4794 * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4795 * merged into it when possible.
4798 SAFSS_RemoveDir (struct rx_call *acall,
4799 struct AFSFid *DirFid,
4801 struct AFSFetchStatus *OutDirStatus,
4802 struct AFSVolSync *Sync)
4805 Vnode * parentptr = 0; /* vnode of input Directory */
4806 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4807 Vnode * targetptr = 0; /* file to be deleted */
4808 AFSFid fileFid; /* area for Fid from the directory */
4809 int errorCode = 0; /* error code */
4810 DirHandle dir; /* Handle for dir package I/O */
4811 Volume * volptr = 0; /* pointer to the volume header */
4812 struct client * client; /* pointer to client structure */
4813 afs_int32 rights, anyrights; /* rights for this and any user */
4814 Vnode debugvnode1, debugvnode2;
4815 struct client *t_client; /* tmp ptr to client data */
4816 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4817 struct rx_connection *tcon = rx_ConnectionOf(acall);
4821 /* Get ptr to client data for user Id for logging */
4822 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4823 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4824 ViceLog(1, ("SAFS_RemoveDir %s, Did = %u.%d.%d, Host %s, Id %d\n",
4825 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4826 inet_ntoa(logHostAddr), t_client->ViceId));
4828 AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
4831 * Get the vnode and volume for the parent dir along with the caller's
4834 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4835 MustBeDIR, &parentwhentargetnotdir,
4836 &client, WRITE_LOCK, &rights, &anyrights))) {
4839 debugvnode1 = *parentptr;
4841 /* set volume synchronization information */
4842 SetVolumeSync(Sync, volptr);
4844 /* Does the caller has delete (&write) access to the parent dir? */
4845 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
4849 debugvnode2 = *parentptr;
4850 /* Do the actual delete of the desired (empty) directory, Name */
4851 if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
4852 Name, MustBeDIR))) {
4856 /* Update the status for the parent dir; link count is also adjusted */
4857 #if FS_STATS_DETAILED
4858 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4859 parentptr->disk.linkCount-1, client->InSameNetwork);
4861 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4862 parentptr->disk.linkCount-1);
4863 #endif /* FS_STATS_DETAILED */
4865 /* Return to the caller the updated parent dir status */
4866 GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4869 * Note: it is not necessary to break the callback on fileFid, since
4870 * refcount is now 0, so no one should be able to refer to the dir
4873 DeleteFileCallBacks(&fileFid);
4875 /* convert the write lock to a read lock before breaking callbacks */
4876 VVnodeWriteToRead(&errorCode, parentptr);
4877 assert(!errorCode || errorCode == VSALVAGE);
4879 /* break call back on DirFid and fileFid */
4880 BreakCallBack(client->host, DirFid, 0);
4883 /* Write the all modified vnodes (parent, new files) and volume back */
4884 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4886 ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
4889 } /*SAFSS_RemoveDir*/
4892 afs_int32 SRXAFS_RemoveDir (struct rx_call *acall,
4893 struct AFSFid *DirFid,
4895 struct AFSFetchStatus *OutDirStatus,
4896 struct AFSVolSync *Sync)
4899 struct rx_connection *tcon;
4900 #if FS_STATS_DETAILED
4901 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4902 struct timeval opStartTime,
4903 opStopTime; /* Start/stop times for RPC op*/
4904 struct timeval elapsedTime; /* Transfer time */
4907 * Set our stats pointer, remember when the RPC operation started, and
4908 * tally the operation.
4910 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
4914 TM_GetTimeOfDay(&opStartTime, 0);
4915 #endif /* FS_STATS_DETAILED */
4917 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4920 code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
4923 CallPostamble(tcon);
4925 #if FS_STATS_DETAILED
4926 TM_GetTimeOfDay(&opStopTime, 0);
4929 (opP->numSuccesses)++;
4930 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4931 fs_stats_AddTo((opP->sumTime), elapsedTime);
4932 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4933 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4934 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4936 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4937 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4942 #endif /* FS_STATS_DETAILED */
4944 osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4947 } /*SRXAFS_RemoveDir*/
4951 * This routine is called exclusively by SRXAFS_SetLock(), and should be
4952 * merged into it when possible.
4955 SAFSS_SetLock (struct rx_call *acall,
4958 struct AFSVolSync *Sync)
4960 Vnode * targetptr = 0; /* vnode of input file */
4961 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4962 int errorCode = 0; /* error code */
4963 Volume * volptr = 0; /* pointer to the volume header */
4964 struct client * client; /* pointer to client structure */
4965 afs_int32 rights, anyrights; /* rights for this and any user */
4966 struct client *t_client; /* tmp ptr to client data */
4967 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4968 static char * locktype[2] = {"LockRead","LockWrite"};
4969 struct rx_connection *tcon = rx_ConnectionOf(acall);
4971 if (type != LockRead && type != LockWrite) {
4975 /* Get ptr to client data for user Id for logging */
4976 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4977 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4978 ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
4979 locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
4980 inet_ntoa(logHostAddr), t_client->ViceId));
4982 AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
4986 * Get the vnode and volume for the desired file along with the caller's
4989 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
4990 DONTCHECK, &parentwhentargetnotdir,
4991 &client, WRITE_LOCK, &rights, &anyrights))) {
4995 /* set volume synchronization information */
4996 SetVolumeSync(Sync, volptr);
4998 /* Handle the particular type of set locking, type */
4999 errorCode = HandleLocking(targetptr, rights, type);
5002 /* Write the all modified vnodes (parent, new files) and volume back */
5003 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5005 if ((errorCode == VREADONLY) && (type == LockRead))
5006 errorCode = 0; /* allow read locks on RO volumes without saving state */
5008 ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
5014 afs_int32 SRXAFS_OldSetLock(struct rx_call *acall,
5017 struct AFSVolSync *Sync)
5019 return SRXAFS_SetLock(acall, Fid, type, Sync);
5021 } /*SRXAFS_OldSetLock*/
5024 afs_int32 SRXAFS_SetLock (struct rx_call *acall,
5027 struct AFSVolSync *Sync)
5030 struct rx_connection *tcon;
5031 #if FS_STATS_DETAILED
5032 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5033 struct timeval opStartTime,
5034 opStopTime; /* Start/stop times for RPC op*/
5035 struct timeval elapsedTime; /* Transfer time */
5038 * Set our stats pointer, remember when the RPC operation started, and
5039 * tally the operation.
5041 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
5045 TM_GetTimeOfDay(&opStartTime, 0);
5046 #endif /* FS_STATS_DETAILED */
5048 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5051 code = SAFSS_SetLock (acall, Fid, type, Sync);
5054 CallPostamble(tcon);
5056 #if FS_STATS_DETAILED
5057 TM_GetTimeOfDay(&opStopTime, 0);
5060 (opP->numSuccesses)++;
5061 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5062 fs_stats_AddTo((opP->sumTime), elapsedTime);
5063 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5064 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5065 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5067 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5068 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5072 #endif /* FS_STATS_DETAILED */
5074 osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
5077 } /*SRXAFS_SetLock*/
5081 * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
5082 * merged into it when possible.
5085 SAFSS_ExtendLock (struct rx_call *acall,
5087 struct AFSVolSync *Sync)
5090 Vnode * targetptr = 0; /* vnode of input file */
5091 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5092 int errorCode = 0; /* error code */
5093 Volume * volptr = 0; /* pointer to the volume header */
5094 struct client * client; /* pointer to client structure */
5095 afs_int32 rights, anyrights; /* rights for this and any user */
5096 struct client *t_client; /* tmp ptr to client data */
5097 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
5098 struct rx_connection *tcon = rx_ConnectionOf(acall);
5100 /* Get ptr to client data for user Id for logging */
5101 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
5102 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
5103 ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n",
5104 Fid->Volume, Fid->Vnode, Fid->Unique,
5105 inet_ntoa(logHostAddr), t_client->ViceId));
5107 AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;
5110 * Get the vnode and volume for the desired file along with the caller's
5113 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5114 DONTCHECK, &parentwhentargetnotdir,
5115 &client, WRITE_LOCK, &rights, &anyrights))) {
5116 goto Bad_ExtendLock;
5119 /* set volume synchronization information */
5120 SetVolumeSync(Sync, volptr);
5122 /* Handle the actual lock extension */
5123 errorCode = HandleLocking(targetptr, rights, LockExtend);
5126 /* Put back file's vnode and volume */
5127 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5129 if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */
5130 errorCode = 0; /* under our generous policy re RO vols */
5132 ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
5135 } /*SAFSS_ExtendLock*/
5138 afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall,
5140 struct AFSVolSync *Sync)
5142 return SRXAFS_ExtendLock(acall, Fid, Sync);
5144 } /*SRXAFS_OldExtendLock*/
5147 afs_int32 SRXAFS_ExtendLock (struct rx_call *acall,
5149 struct AFSVolSync *Sync)
5152 struct rx_connection *tcon;
5153 #if FS_STATS_DETAILED
5154 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5155 struct timeval opStartTime,
5156 opStopTime; /* Start/stop times for RPC op*/
5157 struct timeval elapsedTime; /* Transfer time */
5160 * Set our stats pointer, remember when the RPC operation started, and
5161 * tally the operation.
5163 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
5167 TM_GetTimeOfDay(&opStartTime, 0);
5168 #endif /* FS_STATS_DETAILED */
5170 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5171 goto Bad_ExtendLock;
5173 code = SAFSS_ExtendLock (acall, Fid, Sync);
5176 CallPostamble(tcon);
5178 #if FS_STATS_DETAILED
5179 TM_GetTimeOfDay(&opStopTime, 0);
5182 (opP->numSuccesses)++;
5183 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5184 fs_stats_AddTo((opP->sumTime), elapsedTime);
5185 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5186 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5187 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5189 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5190 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5195 #endif /* FS_STATS_DETAILED */
5197 osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
5200 } /*SRXAFS_ExtendLock*/
5204 * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
5205 * merged into it when possible.
5208 SAFSS_ReleaseLock (struct rx_call *acall,
5210 struct AFSVolSync *Sync)
5213 Vnode * targetptr = 0; /* vnode of input file */
5214 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5215 int errorCode = 0; /* error code */
5216 Volume * volptr = 0; /* pointer to the volume header */
5217 struct client * client; /* pointer to client structure */
5218 afs_int32 rights, anyrights; /* rights for this and any user */
5219 struct client *t_client; /* tmp ptr to client data */
5220 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
5221 struct rx_connection *tcon = rx_ConnectionOf(acall);
5223 /* Get ptr to client data for user Id for logging */
5224 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
5225 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
5226 ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
5227 Fid->Volume, Fid->Vnode, Fid->Unique,
5228 inet_ntoa(logHostAddr), t_client->ViceId));
5230 AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
5233 * Get the vnode and volume for the desired file along with the caller's
5236 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5237 DONTCHECK, &parentwhentargetnotdir,
5238 &client, WRITE_LOCK, &rights, &anyrights))) {
5239 goto Bad_ReleaseLock;
5242 /* set volume synchronization information */
5243 SetVolumeSync(Sync, volptr);
5245 /* Handle the actual lock release */
5246 if ((errorCode = HandleLocking(targetptr, rights, LockRelease)))
5247 goto Bad_ReleaseLock;
5249 /* if no more locks left, a callback would be triggered here */
5250 if (targetptr->disk.lock.lockCount <= 0) {
5251 /* convert the write lock to a read lock before breaking callbacks */
5252 VVnodeWriteToRead(&errorCode, targetptr);
5253 assert(!errorCode || errorCode == VSALVAGE);
5254 BreakCallBack(client->host, Fid, 0);
5258 /* Put back file's vnode and volume */
5259 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5261 if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */
5262 errorCode = 0; /* under our generous policy re RO vols */
5264 ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
5267 } /*SAFSS_ReleaseLock*/
5270 afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall,
5272 struct AFSVolSync *Sync)
5274 return SRXAFS_ReleaseLock(acall, Fid, Sync);
5276 } /*SRXAFS_OldReleaseLock*/
5279 afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall,
5281 struct AFSVolSync *Sync)
5284 struct rx_connection *tcon;
5285 #if FS_STATS_DETAILED
5286 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5287 struct timeval opStartTime,
5288 opStopTime; /* Start/stop times for RPC op*/
5289 struct timeval elapsedTime; /* Transfer time */
5292 * Set our stats pointer, remember when the RPC operation started, and
5293 * tally the operation.
5295 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
5299 TM_GetTimeOfDay(&opStartTime, 0);
5300 #endif /* FS_STATS_DETAILED */
5302 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5303 goto Bad_ReleaseLock;
5305 code = SAFSS_ReleaseLock (acall, Fid, Sync);
5308 CallPostamble(tcon);
5310 #if FS_STATS_DETAILED
5311 TM_GetTimeOfDay(&opStopTime, 0);
5314 (opP->numSuccesses)++;
5315 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5316 fs_stats_AddTo((opP->sumTime), elapsedTime);
5317 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5318 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5319 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5321 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5322 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5327 #endif /* FS_STATS_DETAILED */
5329 osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
5332 } /*SRXAFS_ReleaseLock*/
5335 void SetSystemStats(struct AFSStatistics *stats)
5337 /* Fix this sometime soon.. */
5338 /* Because hey, it's not like we have a network monitoring protocol... */
5339 struct timeval time;
5341 /* this works on all system types */
5342 TM_GetTimeOfDay(&time, 0);
5343 stats->CurrentTime = time.tv_sec;
5344 } /*SetSystemStats*/
5346 void SetAFSStats(struct AFSStatistics *stats)
5348 extern afs_int32 StartTime, CurrentConnections;
5352 stats->CurrentMsgNumber = 0;
5353 stats->OldestMsgNumber = 0;
5354 stats->StartTime = StartTime;
5355 stats->CurrentConnections = CurrentConnections;
5356 stats->TotalAFSCalls = AFSCallStats.TotalCalls;
5357 stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
5358 stats->FetchDatas = AFSCallStats.FetchData;
5359 stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
5360 seconds = AFSCallStats.AccumFetchTime/1000;
5361 if (seconds <= 0) seconds = 1;
5362 stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
5363 stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
5364 stats->StoreDatas = AFSCallStats.StoreData;
5365 stats->StoredBytes = AFSCallStats.TotalStoredBytes;
5366 seconds = AFSCallStats.AccumStoreTime/1000;
5367 if (seconds <= 0) seconds = 1;
5368 stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
5370 stats->ProcessSize = -1; /* TODO: */
5372 stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
5375 h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
5376 (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
5380 /* Get disk related information from all AFS partitions. */
5382 void SetVolumeStats(struct AFSStatistics *stats)
5384 struct DiskPartition * part;
5387 for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
5388 stats->Disks[i].TotalBlocks = part->totalUsable;
5389 stats->Disks[i].BlocksAvailable = part->free;
5390 memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
5391 strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
5394 while (i < AFS_MSTATDISKS) {
5395 stats->Disks[i].TotalBlocks = -1;
5398 } /*SetVolumeStats*/
5400 afs_int32 SRXAFS_GetStatistics (struct rx_call *acall,
5401 struct ViceStatistics *Statistics)
5404 struct rx_connection *tcon;
5405 #if FS_STATS_DETAILED
5406 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5407 struct timeval opStartTime,
5408 opStopTime; /* Start/stop times for RPC op*/
5409 struct timeval elapsedTime; /* Transfer time */
5412 * Set our stats pointer, remember when the RPC operation started, and
5413 * tally the operation.
5415 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
5419 TM_GetTimeOfDay(&opStartTime, 0);
5420 #endif /* FS_STATS_DETAILED */
5422 if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
5423 goto Bad_GetStatistics;
5425 ViceLog(1, ("SAFS_GetStatistics Received\n"));
5427 AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
5429 memset(Statistics, 0, sizeof(*Statistics));
5430 SetAFSStats((struct AFSStatistics *)Statistics);
5431 SetVolumeStats((struct AFSStatistics *)Statistics);
5432 SetSystemStats((struct AFSStatistics *)Statistics);
5435 CallPostamble(tcon);
5437 #if FS_STATS_DETAILED
5438 TM_GetTimeOfDay(&opStopTime, 0);
5441 (opP->numSuccesses)++;
5442 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5443 fs_stats_AddTo((opP->sumTime), elapsedTime);
5444 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5445 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5446 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5448 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5449 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5453 #endif /* FS_STATS_DETAILED */
5457 } /*SRXAFS_GetStatistics*/
5460 /*------------------------------------------------------------------------
5461 * EXPORTED SRXAFS_XStatsVersion
5464 * Routine called by the server-side RPC interface to implement
5465 * pulling out the xstat version number for the File Server.
5468 * a_versionP : Ptr to the version number variable to set.
5474 * Nothing interesting.
5478 *------------------------------------------------------------------------*/
5480 afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
5481 { /*SRXAFS_XStatsVersion*/
5483 #if FS_STATS_DETAILED
5484 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5485 struct timeval opStartTime,
5486 opStopTime; /* Start/stop times for RPC op*/
5487 struct timeval elapsedTime; /* Transfer time */
5490 * Set our stats pointer, remember when the RPC operation started, and
5491 * tally the operation.
5493 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
5497 TM_GetTimeOfDay(&opStartTime, 0);
5498 #endif /* FS_STATS_DETAILED */
5500 *a_versionP = AFS_XSTAT_VERSION;
5502 #if FS_STATS_DETAILED
5503 TM_GetTimeOfDay(&opStopTime, 0);
5504 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5505 fs_stats_AddTo((opP->sumTime), elapsedTime);
5506 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5507 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5508 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5510 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5511 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5514 (opP->numSuccesses)++;
5516 #endif /* FS_STATS_DETAILED */
5520 } /*SRXAFS_XStatsVersion*/
5523 /*------------------------------------------------------------------------
5524 * PRIVATE FillPerfValues
5527 * Routine called to fill a regular performance data structure.
5530 * a_perfP : Ptr to perf structure to fill
5536 * Various collections need this info, so the guts were put in
5537 * this separate routine.
5541 *------------------------------------------------------------------------*/
5543 static void FillPerfValues(struct afs_PerfStats *a_perfP)
5544 { /*FillPerfValues*/
5546 int dir_Buffers; /*# buffers in use by dir package*/
5547 int dir_Calls; /*# read calls in dir package*/
5548 int dir_IOs; /*# I/O ops in dir package*/
5551 * Vnode cache section.
5553 a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
5554 a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
5555 a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
5556 a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
5557 a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
5558 a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
5559 a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
5560 a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
5561 a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
5562 a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
5563 a_perfP->vcache_H_Entries = VolumeCacheSize;
5564 a_perfP->vcache_H_Gets = VolumeGets;
5565 a_perfP->vcache_H_Replacements = VolumeReplacements;
5568 * Directory section.
5570 DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
5571 a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
5572 a_perfP->dir_Calls = (afs_int32 )dir_Calls;
5573 a_perfP->dir_IOs = (afs_int32) dir_IOs;
5578 a_perfP->rx_packetRequests =
5579 (afs_int32) rx_stats.packetRequests;
5580 a_perfP->rx_noPackets_RcvClass =
5581 (afs_int32) rx_stats.receivePktAllocFailures;
5582 a_perfP->rx_noPackets_SendClass =
5583 (afs_int32) rx_stats.sendPktAllocFailures;
5584 a_perfP->rx_noPackets_SpecialClass =
5585 (afs_int32) rx_stats.specialPktAllocFailures;
5586 a_perfP->rx_socketGreedy =
5587 (afs_int32) rx_stats.socketGreedy;
5588 a_perfP->rx_bogusPacketOnRead =
5589 (afs_int32) rx_stats.bogusPacketOnRead;
5590 a_perfP->rx_bogusHost =
5591 (afs_int32) rx_stats.bogusHost;
5592 a_perfP->rx_noPacketOnRead =
5593 (afs_int32) rx_stats.noPacketOnRead;
5594 a_perfP->rx_noPacketBuffersOnRead =
5595 (afs_int32) rx_stats.noPacketBuffersOnRead;
5596 a_perfP->rx_selects =
5597 (afs_int32) rx_stats.selects;
5598 a_perfP->rx_sendSelects =
5599 (afs_int32) rx_stats.sendSelects;
5600 a_perfP->rx_packetsRead_RcvClass =
5601 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
5602 a_perfP->rx_packetsRead_SendClass =
5603 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
5604 a_perfP->rx_packetsRead_SpecialClass =
5605 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
5606 a_perfP->rx_dataPacketsRead =
5607 (afs_int32) rx_stats.dataPacketsRead;
5608 a_perfP->rx_ackPacketsRead =
5609 (afs_int32) rx_stats.ackPacketsRead;
5610 a_perfP->rx_dupPacketsRead =
5611 (afs_int32) rx_stats.dupPacketsRead;
5612 a_perfP->rx_spuriousPacketsRead =
5613 (afs_int32) rx_stats.spuriousPacketsRead;
5614 a_perfP->rx_packetsSent_RcvClass =
5615 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
5616 a_perfP->rx_packetsSent_SendClass =
5617 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
5618 a_perfP->rx_packetsSent_SpecialClass =
5619 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
5620 a_perfP->rx_ackPacketsSent =
5621 (afs_int32) rx_stats.ackPacketsSent;
5622 a_perfP->rx_pingPacketsSent =
5623 (afs_int32) rx_stats.pingPacketsSent;
5624 a_perfP->rx_abortPacketsSent =
5625 (afs_int32) rx_stats.abortPacketsSent;
5626 a_perfP->rx_busyPacketsSent =
5627 (afs_int32) rx_stats.busyPacketsSent;
5628 a_perfP->rx_dataPacketsSent =
5629 (afs_int32) rx_stats.dataPacketsSent;
5630 a_perfP->rx_dataPacketsReSent =
5631 (afs_int32) rx_stats.dataPacketsReSent;
5632 a_perfP->rx_dataPacketsPushed =
5633 (afs_int32) rx_stats.dataPacketsPushed;
5634 a_perfP->rx_ignoreAckedPacket =
5635 (afs_int32) rx_stats.ignoreAckedPacket;
5636 a_perfP->rx_totalRtt_Sec =
5637 (afs_int32) rx_stats.totalRtt.sec;
5638 a_perfP->rx_totalRtt_Usec =
5639 (afs_int32) rx_stats.totalRtt.usec;
5640 a_perfP->rx_minRtt_Sec =
5641 (afs_int32) rx_stats.minRtt.sec;
5642 a_perfP->rx_minRtt_Usec =
5643 (afs_int32) rx_stats.minRtt.usec;
5644 a_perfP->rx_maxRtt_Sec =
5645 (afs_int32) rx_stats.maxRtt.sec;
5646 a_perfP->rx_maxRtt_Usec =
5647 (afs_int32) rx_stats.maxRtt.usec;
5648 a_perfP->rx_nRttSamples =
5649 (afs_int32) rx_stats.nRttSamples;
5650 a_perfP->rx_nServerConns =
5651 (afs_int32) rx_stats.nServerConns;
5652 a_perfP->rx_nClientConns =
5653 (afs_int32) rx_stats.nClientConns;
5654 a_perfP->rx_nPeerStructs =
5655 (afs_int32) rx_stats.nPeerStructs;
5656 a_perfP->rx_nCallStructs =
5657 (afs_int32) rx_stats.nCallStructs;
5658 a_perfP->rx_nFreeCallStructs =
5659 (afs_int32) rx_stats.nFreeCallStructs;
5661 a_perfP->host_NumHostEntries = HTs;
5662 a_perfP->host_HostBlocks = HTBlocks;
5663 h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
5664 &(a_perfP->host_HostsInSameNetOrSubnet),
5665 &(a_perfP->host_HostsInDiffSubnet),
5666 &(a_perfP->host_HostsInDiffNetwork));
5667 a_perfP->host_NumClients = CEs;
5668 a_perfP->host_ClientBlocks = CEBlocks;
5670 a_perfP->sysname_ID = afs_perfstats.sysname_ID;
5672 } /*FillPerfValues*/
5675 /*------------------------------------------------------------------------
5676 * EXPORTED SRXAFS_GetXStats
5679 * Routine called by the server-side callback RPC interface to
5680 * implement getting the given data collection from the extended
5681 * File Server statistics.
5684 * a_call : Ptr to Rx call on which this request came in.
5685 * a_clientVersionNum : Client version number.
5686 * a_opCode : Desired operation.
5687 * a_serverVersionNumP : Ptr to version number to set.
5688 * a_timeP : Ptr to time value (seconds) to set.
5689 * a_dataP : Ptr to variable array structure to return
5696 * Nothing interesting.
5700 *------------------------------------------------------------------------*/
5702 afs_int32 SRXAFS_GetXStats(struct rx_call *a_call,
5703 afs_int32 a_clientVersionNum,
5704 afs_int32 a_collectionNumber,
5705 afs_int32 *a_srvVersionNumP,
5707 AFS_CollData *a_dataP)
5708 { /*SRXAFS_GetXStats*/
5710 register int code; /*Return value*/
5711 afs_int32 *dataBuffP; /*Ptr to data to be returned*/
5712 afs_int32 dataBytes; /*Bytes in data buffer*/
5713 #if FS_STATS_DETAILED
5714 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5715 struct timeval opStartTime,
5716 opStopTime; /* Start/stop times for RPC op*/
5717 struct timeval elapsedTime; /* Transfer time */
5720 * Set our stats pointer, remember when the RPC operation started, and
5721 * tally the operation.
5723 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
5727 TM_GetTimeOfDay(&opStartTime, 0);
5728 #endif /* FS_STATS_DETAILED */
5731 * Record the time of day and the server version number.
5733 *a_srvVersionNumP = AFS_XSTAT_VERSION;
5734 *a_timeP = FT_ApproxTime();
5737 * Stuff the appropriate data in there (assume victory)
5741 ViceLog(1, ("Received GetXStats call for collection %d\n", a_collectionNumber));
5745 * We're not keeping stats, so just return successfully with
5748 a_dataP->AFS_CollData_len = 0;
5749 a_dataP->AFS_CollData_val = NULL;
5752 switch(a_collectionNumber) {
5753 case AFS_XSTATSCOLL_CALL_INFO:
5755 * Pass back all the call-count-related data.
5757 * >>> We are forced to allocate a separate area in which to
5758 * >>> put this stuff in by the RPC stub generator, since it
5759 * >>> will be freed at the tail end of the server stub code.
5763 * I don't think call-level stats are being collected yet
5764 * for the File Server.
5766 dataBytes = sizeof(struct afs_Stats);
5767 dataBuffP = (afs_int32 *)malloc(dataBytes);
5768 memcpy(dataBuffP, &afs_cmstats, dataBytes);
5769 a_dataP->AFS_CollData_len = dataBytes>>2;
5770 a_dataP->AFS_CollData_val = dataBuffP;
5772 a_dataP->AFS_CollData_len = 0;
5773 a_dataP->AFS_CollData_val = NULL;
5777 case AFS_XSTATSCOLL_PERF_INFO:
5779 * Pass back all the regular performance-related data.
5781 * >>> We are forced to allocate a separate area in which to
5782 * >>> put this stuff in by the RPC stub generator, since it
5783 * >>> will be freed at the tail end of the server stub code.
5786 afs_perfstats.numPerfCalls++;
5787 FillPerfValues(&afs_perfstats);
5790 * Don't overwrite the spares at the end.
5793 dataBytes = sizeof(struct afs_PerfStats);
5794 dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5795 memcpy(dataBuffP, &afs_perfstats, dataBytes);
5796 a_dataP->AFS_CollData_len = dataBytes>>2;
5797 a_dataP->AFS_CollData_val = dataBuffP;
5800 case AFS_XSTATSCOLL_FULL_PERF_INFO:
5802 * Pass back the full collection of performance-related data.
5803 * We have to stuff the basic, overall numbers in, but the
5804 * detailed numbers are kept in the structure already.
5806 * >>> We are forced to allocate a separate area in which to
5807 * >>> put this stuff in by the RPC stub generator, since it
5808 * >>> will be freed at the tail end of the server stub code.
5811 afs_perfstats.numPerfCalls++;
5812 #if FS_STATS_DETAILED
5813 afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
5814 FillPerfValues(&afs_FullPerfStats.overall);
5817 * Don't overwrite the spares at the end.
5820 dataBytes = sizeof(struct fs_stats_FullPerfStats);
5821 dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5822 memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
5823 a_dataP->AFS_CollData_len = dataBytes>>2;
5824 a_dataP->AFS_CollData_val = dataBuffP;
5830 * Illegal collection number.
5832 a_dataP->AFS_CollData_len = 0;
5833 a_dataP->AFS_CollData_val = NULL;
5835 } /*Switch on collection number*/
5837 #if FS_STATS_DETAILED
5838 TM_GetTimeOfDay(&opStopTime, 0);
5841 (opP->numSuccesses)++;
5842 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5843 fs_stats_AddTo((opP->sumTime), elapsedTime);
5844 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5845 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5846 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5848 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5849 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5854 #endif /* FS_STATS_DETAILED */
5858 } /*SRXAFS_GetXStats*/
5861 afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall,
5862 struct AFSCBFids *FidArray,
5863 struct AFSCBs *CallBackArray)
5865 afs_int32 errorCode;
5867 struct client *client;
5868 struct rx_connection *tcon;
5869 #if FS_STATS_DETAILED
5870 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5871 struct timeval opStartTime,
5872 opStopTime; /* Start/stop times for RPC op*/
5873 struct timeval elapsedTime; /* Transfer time */
5876 * Set our stats pointer, remember when the RPC operation started, and
5877 * tally the operation.
5879 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
5883 TM_GetTimeOfDay(&opStartTime, 0);
5884 #endif /* FS_STATS_DETAILED */
5886 ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
5888 AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
5890 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
5891 goto Bad_GiveUpCallBacks;
5893 if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
5894 ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n",
5895 FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len,
5896 (tcon->peer ? tcon->peer->host : 0)));
5898 goto Bad_GiveUpCallBacks;
5901 errorCode = GetClient(tcon, &client);
5903 for (i=0; i < FidArray->AFSCBFids_len; i++) {
5904 register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
5905 DeleteCallBack(client->host, fid);
5909 Bad_GiveUpCallBacks:
5910 CallPostamble(tcon);
5912 #if FS_STATS_DETAILED
5913 TM_GetTimeOfDay(&opStopTime, 0);
5914 if (errorCode == 0) {
5916 (opP->numSuccesses)++;
5917 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5918 fs_stats_AddTo((opP->sumTime), elapsedTime);
5919 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5920 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5921 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5923 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5924 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5928 #endif /* FS_STATS_DETAILED */
5932 } /*SRXAFS_GiveUpCallBacks*/
5935 afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall,
5937 struct AFSVolumeInfo *avolinfo)
5939 return(VNOVOL); /* XXX Obsolete routine XXX */
5941 } /*SRXAFS_NGetVolumeInfo*/
5945 * Dummy routine. Should never be called (the cache manager should only
5946 * invoke this interface when communicating with a AFS/DFS Protocol
5949 afs_int32 SRXAFS_Lookup(struct rx_call *call_p,
5950 struct AFSFid *afs_dfid_p,
5952 struct AFSFid *afs_fid_p,
5953 struct AFSFetchStatus *afs_status_p,
5954 struct AFSFetchStatus *afs_dir_status_p,
5955 struct AFSCallBack *afs_callback_p,
5956 struct AFSVolSync *afs_sync_p)
5962 afs_int32 SRXAFS_FlushCPS(struct rx_call *acall,
5963 struct ViceIds *vids,
5964 struct IPAddrs *addrs,
5970 afs_int32 nids, naddrs;
5971 afs_int32 *vd, *addr;
5972 int errorCode = 0; /* return code to caller */
5973 struct client *client;
5974 struct rx_connection *tcon = rx_ConnectionOf(acall);
5976 ViceLog(1, ("SRXAFS_FlushCPS\n"));
5978 AFSCallStats.TotalCalls++;
5980 nids = vids->ViceIds_len; /* # of users in here */
5981 naddrs = addrs->IPAddrs_len; /* # of hosts in here */
5982 if (nids < 0 || naddrs < 0) {
5987 vd = vids->ViceIds_val;
5988 for (i=0; i<nids; i++, vd++) {
5991 client = h_ID2Client(*vd); /* returns client locked, or NULL */
5995 BoostSharedLock(&client->lock);
5996 client->prfail = 2; /* Means re-eval client's cps */
5999 rx_SetRock(((struct rx_connection *) client->tcon), 0);
6002 if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
6003 free(client->CPS.prlist_val);
6004 client->CPS.prlist_val = NULL;
6005 client->CPS.prlist_len = 0;
6007 ReleaseWriteLock(&client->lock);
6010 addr = addrs->IPAddrs_val;
6011 for (i=0; i<naddrs; i++, addr++) {
6013 h_flushhostcps(*addr, 7001);
6017 ViceLog(2, ("SAFS_FlushCPS returns %d\n", errorCode));
6019 } /*SRXAFS_FlushCPS */
6021 /* worthless hack to let CS keep running ancient software */
6022 static int afs_vtoi(register char *aname)
6024 register afs_int32 temp;
6028 while((tc = *aname++)) {
6029 if (tc > '9' || tc < '0') return 0; /* invalid name */
6037 * may get name or #, but must handle all weird cases (recognize readonly
6038 * or backup volumes by name or #
6040 static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave,
6041 register struct VolumeInfo *av)
6043 register int i, j, vol;
6044 afs_int32 mask, whichType;
6045 afs_uint32 *serverHost, *typePtr;
6047 /* figure out what type we want if by name */
6049 if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
6050 whichType = BACKVOL;
6051 else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
6053 else whichType = RWVOL;
6055 vol = afs_vtoi(aname);
6056 if (vol == 0) vol = ave->volumeId[whichType];
6059 * Now vol has volume # we're interested in. Next, figure out the type
6060 * of the volume by looking finding it in the vldb entry
6062 if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
6066 else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
6070 else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
6071 mask = VLSF_RWVOL; /* backup always is on the same volume as parent */
6072 whichType = BACKVOL;
6075 return EINVAL; /* error: can't find volume in vldb entry */
6077 typePtr = &av->Type0;
6078 serverHost = &av->Server0;
6080 av->Type = whichType;
6081 av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
6082 if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
6083 if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
6084 if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
6086 for(i=0,j=0; i<ave->nServers; i++) {
6087 if ((ave->serverFlags[i] & mask) == 0) continue; /* wrong volume */
6088 serverHost[j] = ave->serverNumber[i];
6091 av->ServerCount = j;
6092 if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
6096 static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo)
6098 static struct rx_connection *vlConn = 0;
6099 static int down = 0;
6100 static afs_int32 lastDownTime = 0;
6101 struct vldbentry tve;
6102 struct rx_securityClass *vlSec;
6103 register afs_int32 code;
6106 vlSec = rxnull_NewClientSecurityObject();
6107 vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
6108 rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
6110 if (down && (FT_ApproxTime() < lastDownTime + 180)) {
6111 return 1; /* failure */
6114 code = VL_GetEntryByNameO(vlConn, avolid, &tve);
6115 if (code >= 0) down = 0; /* call worked */
6118 lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
6124 /* otherwise convert to old format vldb entry */
6125 code = CopyVolumeEntry(avolid, &tve, avolinfo);
6134 afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall,
6136 struct VolumeInfo *avolinfo)
6139 struct rx_connection *tcon;
6140 #if FS_STATS_DETAILED
6141 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6142 struct timeval opStartTime,
6143 opStopTime; /* Start/stop times for RPC op*/
6144 struct timeval elapsedTime; /* Transfer time */
6147 * Set our stats pointer, remember when the RPC operation started, and
6148 * tally the operation.
6150 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
6154 TM_GetTimeOfDay(&opStartTime, 0);
6155 #endif /* FS_STATS_DETAILED */
6156 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6157 goto Bad_GetVolumeInfo;
6160 AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
6163 code = TryLocalVLServer(avolid, avolinfo);
6164 ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
6165 code, avolinfo->Vid, avolinfo->Type,
6166 avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
6167 avolinfo->Server3));
6168 avolinfo->Type4 = 0xabcd9999; /* tell us to try new vldb */
6171 CallPostamble(tcon);
6173 #if FS_STATS_DETAILED
6174 TM_GetTimeOfDay(&opStopTime, 0);
6177 (opP->numSuccesses)++;
6178 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6179 fs_stats_AddTo((opP->sumTime), elapsedTime);
6180 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6181 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6182 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6184 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6185 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6190 #endif /* FS_STATS_DETAILED */
6194 } /*SRXAFS_GetVolumeInfo*/
6197 afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall,
6199 AFSFetchVolumeStatus *FetchVolStatus,
6204 Vnode * targetptr = 0; /* vnode of the new file */
6205 Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6206 int errorCode = 0; /* error code */
6207 Volume * volptr = 0; /* pointer to the volume header */
6208 struct client * client; /* pointer to client entry */
6209 afs_int32 rights, anyrights; /* rights for this and any user */
6211 struct rx_connection *tcon;
6212 #if FS_STATS_DETAILED
6213 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6214 struct timeval opStartTime,
6215 opStopTime; /* Start/stop times for RPC op*/
6216 struct timeval elapsedTime; /* Transfer time */
6219 * Set our stats pointer, remember when the RPC operation started, and
6220 * tally the operation.
6222 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
6226 TM_GetTimeOfDay(&opStartTime, 0);
6227 #endif /* FS_STATS_DETAILED */
6229 ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
6230 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6231 goto Bad_GetVolumeStatus;
6234 AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
6239 goto Bad_GetVolumeStatus;
6241 dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6243 if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6244 MustBeDIR, &parentwhentargetnotdir,
6245 &client, READ_LOCK, &rights, &anyrights)))
6246 goto Bad_GetVolumeStatus;
6248 if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
6250 goto Bad_GetVolumeStatus;
6252 RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
6254 Bad_GetVolumeStatus:
6255 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6256 ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
6257 /* next is to guarantee out strings exist for stub */
6258 if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
6259 if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
6260 if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
6261 CallPostamble(tcon);
6263 #if FS_STATS_DETAILED
6264 TM_GetTimeOfDay(&opStopTime, 0);
6265 if (errorCode == 0) {
6267 (opP->numSuccesses)++;
6268 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6269 fs_stats_AddTo((opP->sumTime), elapsedTime);
6270 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6271 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6272 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6274 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6275 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6280 #endif /* FS_STATS_DETAILED */
6283 } /*SRXAFS_GetVolumeStatus*/
6286 afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall,
6288 AFSStoreVolumeStatus *StoreVolStatus,
6293 Vnode * targetptr = 0; /* vnode of the new file */
6294 Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6295 int errorCode = 0; /* error code */
6296 Volume * volptr = 0; /* pointer to the volume header */
6297 struct client * client; /* pointer to client entry */
6298 afs_int32 rights, anyrights; /* rights for this and any user */
6300 struct rx_connection *tcon = rx_ConnectionOf(acall);
6301 #if FS_STATS_DETAILED
6302 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6303 struct timeval opStartTime,
6304 opStopTime; /* Start/stop times for RPC op*/
6305 struct timeval elapsedTime; /* Transfer time */
6308 * Set our stats pointer, remember when the RPC operation started, and
6309 * tally the operation.
6311 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
6315 TM_GetTimeOfDay(&opStartTime, 0);
6316 #endif /* FS_STATS_DETAILED */
6318 ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
6319 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6320 goto Bad_SetVolumeStatus;
6323 AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
6328 goto Bad_SetVolumeStatus;
6330 dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6332 if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6333 MustBeDIR, &parentwhentargetnotdir,
6334 &client, READ_LOCK, &rights, &anyrights)))
6335 goto Bad_SetVolumeStatus;
6337 if (readonlyServer) {
6338 errorCode = VREADONLY;
6339 goto Bad_SetVolumeStatus;
6341 if (VanillaUser(client)) {
6343 goto Bad_SetVolumeStatus;
6346 errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
6349 Bad_SetVolumeStatus:
6350 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6351 ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
6352 CallPostamble(tcon);
6354 #if FS_STATS_DETAILED
6355 TM_GetTimeOfDay(&opStopTime, 0);
6356 if (errorCode == 0) {
6358 (opP->numSuccesses)++;
6359 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6360 fs_stats_AddTo((opP->sumTime), elapsedTime);
6361 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6362 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6363 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6365 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6366 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6371 #endif /* FS_STATS_DETAILED */
6373 osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
6376 } /*SRXAFS_SetVolumeStatus*/
6378 #define DEFAULTVOLUME "root.afs"
6380 afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName)
6385 int errorCode = 0; /* error code */
6386 struct rx_connection *tcon;
6387 #if FS_STATS_DETAILED
6388 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6389 struct timeval opStartTime,
6390 opStopTime; /* Start/stop times for RPC op*/
6391 struct timeval elapsedTime; /* Transfer time */
6394 * Set our stats pointer, remember when the RPC operation started, and
6395 * tally the operation.
6397 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
6401 TM_GetTimeOfDay(&opStartTime, 0);
6402 #endif /* FS_STATS_DETAILED */
6404 return FSERR_EOPNOTSUPP;
6407 if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
6408 goto Bad_GetRootVolume;
6410 AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
6414 fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
6416 strcpy(temp, DEFAULTVOLUME);
6418 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6419 lockf(fd, F_LOCK, 0);
6423 len = read(fd, temp, 256);
6424 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6425 lockf(fd, F_ULOCK, 0);
6430 if (temp[len-1] == '\n') len--;
6433 *VolumeName = temp; /* freed by rx server-side stub */
6436 CallPostamble(tcon);
6438 #if FS_STATS_DETAILED
6439 TM_GetTimeOfDay(&opStopTime, 0);
6440 if (errorCode == 0) {
6442 (opP->numSuccesses)++;
6443 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6444 fs_stats_AddTo((opP->sumTime), elapsedTime);
6445 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6446 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6447 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6449 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6450 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6454 #endif /* FS_STATS_DETAILED */
6459 } /*SRXAFS_GetRootVolume*/
6462 /* still works because a struct CBS is the same as a struct AFSOpaque */
6463 afs_int32 SRXAFS_CheckToken (struct rx_call *acall,
6465 struct AFSOpaque *Token)
6468 struct rx_connection *tcon;
6469 #if FS_STATS_DETAILED
6470 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6471 struct timeval opStartTime,
6472 opStopTime; /* Start/stop times for RPC op*/
6473 struct timeval elapsedTime; /* Transfer time */
6476 * Set our stats pointer, remember when the RPC operation started, and
6477 * tally the operation.
6479 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
6483 TM_GetTimeOfDay(&opStartTime, 0);
6484 #endif /* FS_STATS_DETAILED */
6486 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6487 goto Bad_CheckToken;
6489 code = FSERR_ECONNREFUSED;
6492 CallPostamble(tcon);
6494 #if FS_STATS_DETAILED
6495 TM_GetTimeOfDay(&opStopTime, 0);
6498 (opP->numSuccesses)++;
6499 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6500 fs_stats_AddTo((opP->sumTime), elapsedTime);
6501 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6502 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6503 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6505 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6506 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6511 #endif /* FS_STATS_DETAILED */
6515 } /*SRXAFS_CheckToken*/
6517 afs_int32 SRXAFS_GetTime (struct rx_call *acall,
6518 afs_uint32 *Seconds,
6519 afs_uint32 *USeconds)
6522 struct rx_connection *tcon;
6524 #if FS_STATS_DETAILED
6525 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6526 struct timeval opStartTime,
6527 opStopTime; /* Start/stop times for RPC op*/
6528 struct timeval elapsedTime; /* Transfer time */
6531 * Set our stats pointer, remember when the RPC operation started, and
6532 * tally the operation.
6534 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
6538 TM_GetTimeOfDay(&opStartTime, 0);
6539 #endif /* FS_STATS_DETAILED */
6541 if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
6545 AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
6548 TM_GetTimeOfDay(&tpl, 0);
6549 *Seconds = tpl.tv_sec;
6550 *USeconds = tpl.tv_usec;
6552 ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
6555 CallPostamble(tcon);
6557 #if FS_STATS_DETAILED
6558 TM_GetTimeOfDay(&opStopTime, 0);
6559 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6562 (opP->numSuccesses)++;
6563 fs_stats_AddTo((opP->sumTime), elapsedTime);
6564 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6565 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6566 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6568 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6569 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6574 #endif /* FS_STATS_DETAILED */
6578 } /*SRXAFS_GetTime*/
6585 * Implement a client's data fetch using Rx.
6588 * volptr : Ptr to the given volume's info.
6589 * targetptr : Pointer to the vnode involved.
6590 * Call : Ptr to the Rx call involved.
6591 * Pos : Offset within the file.
6592 * Len : Length in bytes to read; this value is bogus!
6593 * if FS_STATS_DETAILED
6594 * a_bytesToFetchP : Set to the number of bytes to be fetched from
6596 * a_bytesFetchedP : Set to the actual number of bytes fetched from
6602 FetchData_RXStyle(Volume *volptr,
6604 register struct rx_call *Call,
6607 afs_int32 Int64Mode,
6608 #if FS_STATS_DETAILED
6609 afs_size_t *a_bytesToFetchP,
6610 afs_size_t *a_bytesFetchedP
6611 #endif /* FS_STATS_DETAILED */
6614 struct timeval StartTime, StopTime; /* used to calculate file transfer rates */
6615 int errorCode = 0; /* Returned error code to caller */
6620 register char *tbuffer;
6621 #else /* AFS_NT40_ENV */
6622 struct iovec tiov[RX_MAXIOVECS];
6624 #endif /* AFS_NT40_ENV */
6629 struct statfs tstatfs;
6632 #if FS_STATS_DETAILED
6634 * Initialize the byte count arguments.
6636 (*a_bytesToFetchP) = 0;
6637 (*a_bytesFetchedP) = 0;
6638 #endif /* FS_STATS_DETAILED */
6640 #ifdef AFS_LARGEFILE_ENV
6641 ViceLog(25, ("FetchData_RXStyle: Pos (0X%x,0X%x), Len (0X%x,0X%x)\n",
6642 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6643 (unsigned) (Len >> 32), (unsigned) (Len & 0xffffffff)));
6644 #else /* !AFS_LARGEFILE_ENV */
6645 ViceLog(25, ("FetchData_RXStyle: Pos 0X%x, Len 0X%x\n",
6648 #endif /* !AFS_LARGEFILE_ENV */
6650 if (!VN_GET_INO(targetptr)) {
6651 afs_int32 zero = htonl(0);
6653 * This is used for newly created files; we simply send 0 bytes
6654 * back to make the cache manager happy...
6657 rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* send 0-length */
6658 rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* send 0-length */
6661 TM_GetTimeOfDay(&StartTime, 0);
6662 ihP = targetptr->handle;
6664 if (fdP == NULL) return EIO;
6665 optSize = sendBufSize;
6666 tlen = FDH_SIZE(fdP);
6667 #ifdef AFS_LARGEFILE_ENV
6668 ViceLog( 25, ("FetchData_RXStyle: file size (0X%x,0X%x)\n",
6669 (unsigned) (tlen >> 32), (unsigned) (tlen & 0xffffffff)));
6670 #else /* !AFS_LARGEFILE_ENV */
6671 ViceLog( 25, ("FetchData_RXStyle: file size 0X%x\n",
6673 #endif /* !AFS_LARGEFILE_ENV */
6679 if (Pos + Len > tlen) Len = tlen - Pos; /* get length we should send */
6680 FDH_SEEK(fdP, Pos, 0);
6682 afs_int32 high, low;
6683 SplitOffsetOrSize(Len, high, low);
6684 assert(Int64Mode || high==0);
6687 rx_Write(Call, (char *)&high, sizeof(afs_int32)); /* High order bits */
6690 rx_Write(Call, (char *)&low, sizeof(afs_int32)); /* send length on fetch */
6692 #if FS_STATS_DETAILED
6693 (*a_bytesToFetchP) = Len;
6694 #endif /* FS_STATS_DETAILED */
6696 tbuffer = AllocSendBuffer();
6697 #endif /* AFS_NT40_ENV */
6699 if (Len > optSize) tlen = optSize;
6702 errorCode = FDH_READ(fdP, tbuffer, tlen);
6703 if (errorCode != tlen) {
6705 FreeSendBuffer((struct afs_buffer *) tbuffer);
6708 errorCode = rx_Write(Call, tbuffer, tlen);
6709 #else /* AFS_NT40_ENV */
6710 errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6711 if (errorCode <= 0) {
6716 errorCode = FDH_READV(fdP, tiov, tnio);
6717 if (errorCode != tlen) {
6721 errorCode = rx_Writev(Call, tiov, tnio, tlen);
6722 #endif /* AFS_NT40_ENV */
6723 #if FS_STATS_DETAILED
6725 * Bump the number of bytes actually sent by the number from this
6728 (*a_bytesFetchedP) += errorCode;
6729 #endif /* FS_STATS_DETAILED */
6730 if (errorCode != tlen) {
6733 FreeSendBuffer((struct afs_buffer *) tbuffer);
6734 #endif /* AFS_NT40_ENV */
6740 FreeSendBuffer((struct afs_buffer *) tbuffer);
6741 #endif /* AFS_NT40_ENV */
6743 TM_GetTimeOfDay(&StopTime, 0);
6745 /* Adjust all Fetch Data related stats */
6747 if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
6748 AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
6749 AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
6750 ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
6753 VN_GET_LEN(targLen, targetptr);
6754 AFSCallStats.TotalFetchedBytes += targLen;
6755 AFSCallStats.FetchSize1++;
6756 if (targLen < SIZE2)
6757 AFSCallStats.FetchSize2++;
6758 else if (targLen < SIZE3)
6759 AFSCallStats.FetchSize3++;
6760 else if (targLen < SIZE4)
6761 AFSCallStats.FetchSize4++;
6763 AFSCallStats.FetchSize5++;
6768 } /*FetchData_RXStyle*/
6770 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, afs_size_t *size)
6772 #ifdef AFS_NAMEI_ENV
6774 lhp = IH_OPEN(V_linkHandle(vp));
6778 *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6780 *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6785 *size = OS_SIZE(fdP->fd_fd);
6786 return (*size == -1) ? -1 : 0;
6790 if (fstat(fdP->fd_fd, &status)<0) {
6794 *lc = GetLinkCount(vp, &status);
6795 *size = status.st_size;
6804 * Implement a client's data store using Rx.
6807 * volptr : Ptr to the given volume's info.
6808 * targetptr : Pointer to the vnode involved.
6809 * Call : Ptr to the Rx call involved.
6810 * Pos : Offset within the file.
6811 * Len : Length in bytes to store; this value is bogus!
6812 * if FS_STATS_DETAILED
6813 * a_bytesToStoreP : Set to the number of bytes to be stored to
6815 * a_bytesStoredP : Set to the actual number of bytes stored to
6820 StoreData_RXStyle(Volume *volptr,
6823 struct client *client,
6824 register struct rx_call *Call,
6827 afs_offs_t FileLength,
6829 #if FS_STATS_DETAILED
6830 afs_size_t *a_bytesToStoreP,
6831 afs_size_t *a_bytesStoredP
6832 #endif /* FS_STATS_DETAILED */
6835 afs_size_t bytesTransfered; /* number of bytes actually transfered */
6836 struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
6837 int errorCode = 0; /* Returned error code to caller */
6839 register char *tbuffer; /* data copying buffer */
6840 #else /* AFS_NT40_ENV */
6841 struct iovec tiov[RX_MAXIOVECS]; /* no data copying with iovec */
6842 int tnio; /* temp for iovec size */
6843 #endif /* AFS_NT40_ENV */
6844 afs_size_t tlen; /* temp for xfr length */
6845 Inode tinode; /* inode for I/O */
6846 afs_size_t optSize; /* optimal transfer size */
6847 afs_size_t DataLength; /* size of inode */
6848 afs_size_t TruncatedLength; /* size after ftruncate */
6849 afs_offs_t NewLength; /* size after this store completes */
6850 afs_size_t adjustSize; /* bytes to call VAdjust... with */
6851 int linkCount; /* link count on inode */
6854 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
6856 #if FS_STATS_DETAILED
6858 * Initialize the byte count arguments.
6860 (*a_bytesToStoreP) = 0;
6861 (*a_bytesStoredP) = 0;
6862 #endif /* FS_STATS_DETAILED */
6865 * We break the callbacks here so that the following signal will not
6868 BreakCallBack(client->host, Fid, 0);
6870 if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
6871 /* the inode should have been created in Alloc_NewVnode */
6872 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
6873 ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
6874 Fid->Volume, Fid->Vnode, Fid->Unique,
6875 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
6876 return ENOENT; /* is this proper error code? */
6880 * See if the file has several links (from other volumes). If it
6881 * does, then we have to make a copy before changing it to avoid
6882 *changing read-only clones of this dude
6884 ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
6885 PrintInode(NULL, VN_GET_INO(targetptr))));
6886 fdP = IH_OPEN(targetptr->handle);
6889 if (GetLinkCountAndSize(volptr, fdP, &linkCount,
6895 if (linkCount != 1) {
6897 ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
6898 PrintInode(NULL, VN_GET_INO(targetptr))));
6899 /* other volumes share this data, better copy it first */
6901 /* Adjust the disk block count by the creation of the new inode.
6902 * We call the special VDiskUsage so we don't adjust the volume's
6903 * quota since we don't want to penalyze the user for afs's internal
6904 * mechanisms (i.e. copy on write overhead.) Also the right size
6905 * of the disk will be recorded...
6908 VN_GET_LEN(size, targetptr);
6909 volptr->partition->flags &= ~PART_DONTUPDATE;
6910 VSetPartitionDiskUsage(volptr->partition);
6911 volptr->partition->flags |= PART_DONTUPDATE;
6912 if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
6913 volptr->partition->flags &= ~PART_DONTUPDATE;
6917 ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n"));
6918 if ((errorCode = CopyOnWrite(targetptr, volptr)))
6920 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6921 volptr->partition->flags &= ~PART_DONTUPDATE;
6924 volptr->partition->flags &= ~PART_DONTUPDATE;
6925 VSetPartitionDiskUsage(volptr->partition);
6926 fdP = IH_OPEN(targetptr->handle);
6928 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
6932 tinode = VN_GET_INO(targetptr);
6934 assert(VALID_INO(tinode));
6936 /* compute new file length */
6937 NewLength = DataLength;
6938 if (FileLength < NewLength)
6939 /* simulate truncate */
6940 NewLength = FileLength;
6941 TruncatedLength = NewLength; /* remember length after possible ftruncate */
6942 if (Pos + Length > NewLength)
6943 NewLength = Pos+Length; /* and write */
6945 /* adjust the disk block count by the difference in the files */
6947 afs_size_t targSize;
6948 VN_GET_LEN(targSize, targetptr);
6949 adjustSize = nBlocks(NewLength) - nBlocks(targSize);
6951 if((errorCode = AdjustDiskUsage(volptr, adjustSize,
6952 adjustSize - SpareComp(volptr)))) {
6957 /* can signal cache manager to proceed from close now */
6958 /* this bit means that the locks are set and protections are OK */
6959 rx_SetLocalStatus(Call, 1);
6961 TM_GetTimeOfDay(&StartTime, 0);
6963 optSize = sendBufSize;
6965 #ifdef AFS_LARGEFILE_ENV
6966 ViceLog(25, ("StoreData_RXStyle: Pos (0X%x,0X%x), DataLength (0X%x,0X%x), FileLength (0X%x,0X%x), Length (0X%x,0X%x)\n",
6967 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6968 (unsigned) (DataLength >> 32), (unsigned) (DataLength & 0xffffffff),
6969 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff),
6970 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff)));
6971 #else /* !AFS_LARGEFILE_ENV */
6972 ViceLog(25, ("StoreData_RXStyle: Pos 0X%x, DataLength 0X%x, FileLength 0X%x, Length 0X%x\n",
6974 (unsigned) DataLength,
6975 (unsigned) FileLength,
6976 (unsigned) Length));
6977 #endif /* !AFS_LARGEFILE_ENV */
6979 /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
6980 if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
6981 if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
6982 bytesTransfered = 0;
6984 tbuffer = AllocSendBuffer();
6985 #endif /* AFS_NT40_ENV */
6986 /* if length == 0, the loop below isn't going to do anything, including
6987 * extend the length of the inode, which it must do, since the file system
6988 * assumes that the inode length == vnode's file length. So, we extend
6989 * the file length manually if need be. Note that if file is bigger than
6990 * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
6991 * do what we're going to do below.
6993 if (Length == 0 && Pos > TruncatedLength) {
6994 /* Set the file's length; we've already done an lseek to the right
6997 errorCode = FDH_WRITE(fdP, &tlen, 1);
6998 if (errorCode != 1) goto done;
6999 errorCode = FDH_TRUNC(fdP, Pos);
7002 /* have some data to copy */
7003 #if FS_STATS_DETAILED
7004 (*a_bytesToStoreP) = Length;
7005 #endif /* FS_STATS_DETAILED */
7007 if (bytesTransfered >= Length) {
7011 tlen = Length - bytesTransfered; /* how much more to do */
7012 if (tlen > optSize) tlen = optSize; /* bound by buffer size */
7014 errorCode = rx_Read(Call, tbuffer, tlen);
7015 #else /* AFS_NT40_ENV */
7016 errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
7017 #endif /* AFS_NT40_ENV */
7018 #if FS_STATS_DETAILED
7019 (*a_bytesStoredP) += errorCode;
7020 #endif /* FS_STATS_DETAILED */
7021 if (errorCode <= 0) {
7027 errorCode = FDH_WRITE(fdP, tbuffer, tlen);
7028 #else /* AFS_NT40_ENV */
7029 errorCode = FDH_WRITEV(fdP, tiov, tnio);
7030 #endif /* AFS_NT40_ENV */
7031 if (errorCode != tlen) {
7032 errorCode = VDISKFULL;
7035 bytesTransfered += tlen;
7040 FreeSendBuffer((struct afs_buffer *) tbuffer);
7041 #endif /* AFS_NT40_ENV */
7046 afs_size_t nfSize = FDH_SIZE(fdP);
7047 /* something went wrong: adjust size and return */
7048 VN_SET_LEN(targetptr, nfSize); /* set new file size. */
7049 /* changed_newTime is tested in StoreData to detemine if we
7050 * need to update the target vnode.
7052 targetptr->changed_newTime = 1;
7054 /* set disk usage to be correct */
7055 VAdjustDiskUsage(&errorCode, volptr,
7056 (afs_size_t)(nBlocks(nfSize) - nBlocks(NewLength)),
7062 TM_GetTimeOfDay(&StopTime, 0);
7064 VN_SET_LEN(targetptr, NewLength);
7066 /* Update all StoreData related stats */
7068 if (AFSCallStats.TotalStoredBytes > 2000000000) /* reset if over 2 billion */
7069 AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
7070 AFSCallStats.StoreSize1++; /* Piggybacked data */
7073 VN_GET_LEN(targLen, targetptr);
7074 if (targLen < SIZE2)
7075 AFSCallStats.StoreSize2++;
7076 else if (targLen < SIZE3)
7077 AFSCallStats.StoreSize3++;
7078 else if (targLen < SIZE4)
7079 AFSCallStats.StoreSize4++;
7081 AFSCallStats.StoreSize5++;
7086 } /*StoreData_RXStyle*/