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);
1845 strcpy(*name, V_name(volptr));
1846 temp = strlen(V_offlineMessage(volptr)) + 1;
1847 *offMsg = malloc(temp);
1848 strcpy(*offMsg, V_offlineMessage(volptr));
1849 #if TRANSARC_VOL_STATS
1851 strcpy(*motd, nullString);
1853 temp = strlen(V_motd(volptr)) + 1;
1854 *motd = malloc(temp);
1855 strcpy(*motd, V_motd(volptr));
1856 #endif /* FS_STATS_DETAILED */
1858 } /*RXGetVolumeStatus*/
1862 FileNameOK(register char *aname)
1864 register afs_int32 i, tc;
1867 /* watch for @sys on the right */
1868 if (strcmp(aname+i-4, "@sys") == 0) return 0;
1870 while ((tc = *aname++)) {
1871 if (tc == '/') return 0; /* very bad character to encounter */
1873 return 1; /* file name is ok */
1878 /* Debugging tool to print Volume Statu's contents */
1880 PrintVolumeStatus(VolumeStatus *status)
1882 ViceLog(5,("Volume header contains:\n"));
1883 ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1884 status->Vid, status->ParentId, status->Online, status->InService,
1885 status->Blessed, status->NeedsSalvage));
1886 ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1887 ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1888 status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1890 } /*PrintVolumeStatus*/
1894 * This variant of symlink is expressly to support the AFS/DFS translator
1895 * and is not supported by the AFS fileserver. We just return EINVAL.
1896 * The cache manager should not generate this call to an AFS cache manager.
1898 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1899 struct AFSFid *DirFid,
1902 struct AFSStoreStatus *InStatus,
1903 struct AFSFid *OutFid,
1904 struct AFSFetchStatus *OutFidStatus,
1905 struct AFSFetchStatus *OutDirStatus,
1906 struct AFSCallBack *CallBack,
1907 struct AFSVolSync *Sync)
1912 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1913 struct ResidencyCmdInputs *Inputs,
1914 struct ResidencyCmdOutputs *Outputs)
1919 static struct afs_buffer {
1920 struct afs_buffer *next;
1921 } *freeBufferList = 0;
1922 static int afs_buffersAlloced = 0;
1924 static FreeSendBuffer(register struct afs_buffer *adata)
1927 afs_buffersAlloced--;
1928 adata->next = freeBufferList;
1929 freeBufferList = adata;
1933 } /*FreeSendBuffer*/
1935 /* allocate space for sender */
1936 static char *AllocSendBuffer()
1938 register struct afs_buffer *tp;
1941 afs_buffersAlloced++;
1942 if (!freeBufferList) {
1944 return malloc(sendBufSize);
1946 tp = freeBufferList;
1947 freeBufferList = tp->next;
1951 } /*AllocSendBuffer*/
1954 * This routine returns the status info associated with the targetptr vnode
1955 * in the AFSFetchStatus structure. Some of the newer fields, such as
1956 * SegSize and Group are not yet implemented
1959 void GetStatus(Vnode *targetptr,
1960 AFSFetchStatus *status,
1962 afs_int32 anyrights,
1965 /* initialize return status from a vnode */
1966 status->InterfaceVersion = 1;
1967 status->SyncCounter = status->dataVersionHigh = status->lockCount =
1968 status->errorCode = 0;
1969 status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1970 if (targetptr->disk.type == vFile)
1971 status->FileType = File;
1972 else if (targetptr->disk.type == vDirectory)
1973 status->FileType = Directory;
1974 else if (targetptr->disk.type == vSymlink)
1975 status->FileType = SymbolicLink;
1977 status->FileType = Invalid; /*invalid type field */
1978 status->LinkCount = targetptr->disk.linkCount;
1979 SET_STATUS_LEN(status, targetptr);
1980 status->DataVersion = targetptr->disk.dataVersion;
1981 status->Author = targetptr->disk.author;
1982 status->Owner = targetptr->disk.owner;
1983 status->CallerAccess = rights;
1984 status->AnonymousAccess = anyrights;
1985 status->UnixModeBits = targetptr->disk.modeBits;
1986 status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */
1987 status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
1988 status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
1989 status->ServerModTime = targetptr->disk.serverModifyTime;
1990 status->Group = targetptr->disk.group;
1991 status->lockCount = targetptr->disk.lock.lockCount;
1992 status->errorCode = 0;
1997 afs_int32 common_FetchData64 (struct rx_call *acall,
2001 struct AFSFetchStatus *OutStatus,
2002 struct AFSCallBack *CallBack,
2003 struct AFSVolSync *Sync,
2006 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2007 Vnode * parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */
2008 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2009 int errorCode = 0; /* return code to caller */
2010 int fileCode = 0; /* return code from vol package */
2011 Volume * volptr = 0; /* pointer to the volume */
2012 struct client *client; /* pointer to the client data */
2013 struct rx_connection *tcon; /* the connection we're part of */
2014 afs_int32 rights, anyrights; /* rights for this and any user */
2015 struct client *t_client; /* tmp ptr to client data */
2016 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2017 #if FS_STATS_DETAILED
2018 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2019 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2020 struct timeval opStartTime,
2021 opStopTime; /* Start/stop times for RPC op*/
2022 struct timeval xferStartTime,
2023 xferStopTime; /* Start/stop times for xfer portion*/
2024 struct timeval elapsedTime; /* Transfer time */
2025 afs_size_t bytesToXfer; /* # bytes to xfer*/
2026 afs_size_t bytesXferred; /* # bytes actually xferred*/
2027 int readIdx; /* Index of read stats array to bump*/
2028 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2031 * Set our stats pointers, remember when the RPC operation started, and
2032 * tally the operation.
2034 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2035 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2039 TM_GetTimeOfDay(&opStartTime, 0);
2040 #endif /* FS_STATS_DETAILED */
2042 ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2043 Fid->Volume, Fid->Vnode, Fid->Unique));
2045 AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2048 if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2051 /* Get ptr to client data for user Id for logging */
2052 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2053 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2054 ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2055 Fid->Volume, Fid->Vnode, Fid->Unique,
2056 inet_ntoa(logHostAddr), t_client->ViceId));
2058 * Get volume/vnode for the fetched file; caller's access rights to
2059 * it are also returned
2061 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2062 DONTCHECK, &parentwhentargetnotdir,
2063 &client, READ_LOCK, &rights, &anyrights)))
2066 SetVolumeSync(Sync, volptr);
2068 #if FS_STATS_DETAILED
2070 * Remember that another read operation was performed.
2073 if (client->InSameNetwork)
2074 readIdx = VOL_STATS_SAME_NET;
2076 readIdx = VOL_STATS_DIFF_NET;
2077 V_stat_reads(volptr, readIdx)++;
2078 if (client->ViceId != AnonymousID) {
2079 V_stat_reads(volptr, readIdx+1)++;
2082 #endif /* FS_STATS_DETAILED */
2084 /* Check whether the caller has permission access to fetch the data */
2085 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2090 * Drop the read lock on the parent directory after saving the parent
2091 * vnode information we need to pass to GetStatus
2093 if (parentwhentargetnotdir != NULL) {
2094 tparentwhentargetnotdir = *parentwhentargetnotdir;
2095 VPutVnode(&fileCode, parentwhentargetnotdir);
2096 assert(!fileCode || (fileCode == VSALVAGE));
2097 parentwhentargetnotdir = NULL;
2100 #if FS_STATS_DETAILED
2102 * Remember when the data transfer started.
2104 TM_GetTimeOfDay(&xferStartTime, 0);
2105 #endif /* FS_STATS_DETAILED */
2107 /* actually do the data transfer */
2108 #if FS_STATS_DETAILED
2109 errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2110 (afs_size_t) Pos, (afs_size_t) Len, type,
2111 &bytesToXfer, &bytesXferred);
2113 if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2114 (afs_size_t) Pos, (afs_size_t) Len,
2117 #endif /* FS_STATS_DETAILED */
2119 #if FS_STATS_DETAILED
2121 * At this point, the data transfer is done, for good or ill. Remember
2122 * when the transfer ended, bump the number of successes/failures, and
2123 * integrate the transfer size and elapsed time into the stats. If the
2124 * operation failed, we jump to the appropriate point.
2126 TM_GetTimeOfDay(&xferStopTime, 0);
2128 (xferP->numXfers)++;
2130 (xferP->numSuccesses)++;
2133 * Bump the xfer sum by the number of bytes actually sent, NOT the
2136 tot_bytesXferred += bytesXferred;
2137 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2138 tot_bytesXferred &= 0x3FF;
2139 if (bytesXferred < xferP->minBytes)
2140 xferP->minBytes = bytesXferred;
2141 if (bytesXferred > xferP->maxBytes)
2142 xferP->maxBytes = bytesXferred;
2145 * Tally the size of the object. Note: we tally the actual size,
2146 * NOT the number of bytes that made it out over the wire.
2148 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2149 (xferP->count[0])++;
2151 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2152 (xferP->count[1])++;
2154 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2155 (xferP->count[2])++;
2157 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2158 (xferP->count[3])++;
2160 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2161 (xferP->count[4])++;
2163 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2164 (xferP->count[5])++;
2166 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2167 (xferP->count[6])++;
2169 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2170 (xferP->count[7])++;
2172 (xferP->count[8])++;
2174 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2175 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2176 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2177 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2178 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2180 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2181 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2186 * Finally, go off to tell our caller the bad news in case the
2191 #endif /* FS_STATS_DETAILED */
2193 /* write back the OutStatus from the target vnode */
2194 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2196 /* if a r/w volume, promise a callback to the caller */
2197 if (VolumeWriteable(volptr))
2198 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2200 struct AFSFid myFid;
2201 memset(&myFid, 0, sizeof(struct AFSFid));
2202 myFid.Volume = Fid->Volume;
2203 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2207 /* Update and store volume/vnode and parent vnodes back */
2208 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2209 ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2210 CallPostamble(tcon);
2212 #if FS_STATS_DETAILED
2213 TM_GetTimeOfDay(&opStopTime, 0);
2214 if (errorCode == 0) {
2216 (opP->numSuccesses)++;
2217 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2218 fs_stats_AddTo((opP->sumTime), elapsedTime);
2219 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2220 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2221 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2223 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2224 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2229 #endif /* FS_STATS_DETAILED */
2231 osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2234 } /*common_FetchData64*/
2236 afs_int32 SRXAFS_FetchData (struct rx_call *acall,
2240 struct AFSFetchStatus *OutStatus,
2241 struct AFSCallBack *CallBack,
2242 struct AFSVolSync *Sync)
2247 code = common_FetchData64 (acall, Fid,
2248 (afs_size_t) Pos, (afs_size_t) Len,
2254 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall,
2258 struct AFSFetchStatus *OutStatus,
2259 struct AFSCallBack *CallBack,
2260 struct AFSVolSync *Sync)
2263 afs_size_t tPos, tLen;
2265 #ifdef AFS_64BIT_ENV
2266 #ifndef AFS_LARGEFILE_ENV
2267 if (Pos + Len > 0x7fffffff)
2269 #endif /* !AFS_LARGEFILE_ENV */
2272 #else /* AFS_64BIT_ENV */
2273 if (Pos.high || Len.high)
2277 #endif /* AFS_64BIT_ENV */
2279 code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2284 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,
2286 struct AFSOpaque *AccessList,
2287 struct AFSFetchStatus *OutStatus,
2288 struct AFSVolSync *Sync)
2290 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2291 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2292 int errorCode = 0; /* return error code to caller */
2293 Volume * volptr = 0; /* pointer to the volume */
2294 struct client *client; /* pointer to the client data */
2295 afs_int32 rights, anyrights; /* rights for this and any user */
2296 struct rx_connection *tcon = rx_ConnectionOf(acall);
2297 struct client *t_client; /* tmp ptr to client data */
2298 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2299 #if FS_STATS_DETAILED
2300 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2301 struct timeval opStartTime,
2302 opStopTime; /* Start/stop times for RPC op*/
2303 struct timeval elapsedTime; /* Transfer time */
2306 * Set our stats pointer, remember when the RPC operation started, and
2307 * tally the operation.
2309 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2313 TM_GetTimeOfDay(&opStartTime, 0);
2314 #endif /* FS_STATS_DETAILED */
2316 ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2317 Fid->Volume, Fid->Vnode, Fid->Unique));
2319 AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2321 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2324 /* Get ptr to client data for user Id for logging */
2325 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2326 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2327 ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2328 Fid->Volume, Fid->Vnode, Fid->Unique,
2329 inet_ntoa(logHostAddr), t_client->ViceId));
2331 AccessList->AFSOpaque_len = 0;
2332 AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2335 * Get volume/vnode for the fetched file; caller's access rights to it
2338 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2339 DONTCHECK, &parentwhentargetnotdir,
2340 &client, READ_LOCK, &rights, &anyrights)))
2343 SetVolumeSync(Sync, volptr);
2345 /* Check whether we have permission to fetch the ACL */
2346 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2350 /* Get the Access List from the dir's vnode */
2351 if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2355 /* Get OutStatus back From the target Vnode */
2356 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2359 /* Update and store volume/vnode and parent vnodes back */
2360 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2361 ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2362 errorCode, AccessList->AFSOpaque_val));
2363 CallPostamble(tcon);
2365 #if FS_STATS_DETAILED
2366 TM_GetTimeOfDay(&opStopTime, 0);
2367 if (errorCode == 0) {
2369 (opP->numSuccesses)++;
2370 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2371 fs_stats_AddTo((opP->sumTime), elapsedTime);
2372 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2373 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2374 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2376 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2377 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2382 #endif /* FS_STATS_DETAILED */
2384 osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2386 } /*SRXAFS_FetchACL*/
2390 * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2391 * merged into it when possible.
2394 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2396 struct AFSFetchStatus *OutStatus,
2397 struct AFSCallBack *CallBack,
2398 struct AFSVolSync *Sync)
2400 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2401 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2402 int errorCode = 0; /* return code to caller */
2403 Volume * volptr = 0; /* pointer to the volume */
2404 struct client *client; /* pointer to the client data */
2405 afs_int32 rights, anyrights; /* rights for this and any user */
2406 struct client *t_client; /* tmp ptr to client data */
2407 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2408 struct rx_connection *tcon = rx_ConnectionOf(acall);
2410 /* Get ptr to client data for user Id for logging */
2411 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2412 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2413 ViceLog(1, ("SAFS_FetchStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
2414 Fid->Volume, Fid->Vnode, Fid->Unique,
2415 inet_ntoa(logHostAddr), t_client->ViceId));
2417 AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2420 * Get volume/vnode for the fetched file; caller's rights to it are
2423 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2424 DONTCHECK, &parentwhentargetnotdir,
2425 &client, READ_LOCK, &rights, &anyrights)))
2426 goto Bad_FetchStatus;
2428 /* set volume synchronization information */
2429 SetVolumeSync(Sync, volptr);
2431 /* Are we allowed to fetch Fid's status? */
2432 if (targetptr->disk.type != vDirectory) {
2433 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2434 CHK_FETCHSTATUS, 0))) {
2435 if (rx_GetCallAbortCode(acall) == errorCode)
2436 rx_SetCallAbortCode(acall, 0);
2437 goto Bad_FetchStatus;
2441 /* set OutStatus From the Fid */
2442 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2444 /* If a r/w volume, also set the CallBack state */
2445 if (VolumeWriteable(volptr))
2446 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2448 struct AFSFid myFid;
2449 memset(&myFid, 0, sizeof(struct AFSFid));
2450 myFid.Volume = Fid->Volume;
2451 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2455 /* Update and store volume/vnode and parent vnodes back */
2456 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2457 ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2460 } /*SAFSS_FetchStatus*/
2463 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2464 struct AFSCBFids *Fids,
2465 struct AFSBulkStats *OutStats,
2466 struct AFSCBs *CallBacks,
2467 struct AFSVolSync *Sync)
2471 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2472 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2473 int errorCode = 0; /* return code to caller */
2474 Volume * volptr = 0; /* pointer to the volume */
2475 struct client *client; /* pointer to the client data */
2476 afs_int32 rights, anyrights; /* rights for this and any user */
2477 register struct AFSFid *tfid; /* file id we're dealing with now */
2478 struct rx_connection *tcon = rx_ConnectionOf(acall);
2479 #if FS_STATS_DETAILED
2480 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2481 struct timeval opStartTime,
2482 opStopTime; /* Start/stop times for RPC op*/
2483 struct timeval elapsedTime; /* Transfer time */
2486 * Set our stats pointer, remember when the RPC operation started, and
2487 * tally the operation.
2489 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2493 TM_GetTimeOfDay(&opStartTime, 0);
2494 #endif /* FS_STATS_DETAILED */
2496 ViceLog(1, ("SAFS_BulkStatus\n"));
2498 AFSCallStats.TotalCalls++;
2501 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2502 if (nfiles <= 0) { /* Sanity check */
2504 goto Audit_and_Return;
2507 /* allocate space for return output parameters */
2508 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2509 malloc(nfiles * sizeof(struct AFSFetchStatus));
2510 OutStats->AFSBulkStats_len = nfiles;
2511 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2512 malloc(nfiles * sizeof(struct AFSCallBack));
2513 CallBacks->AFSCBs_len = nfiles;
2515 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2516 goto Bad_BulkStatus;
2518 tfid = Fids->AFSCBFids_val;
2519 for (i=0; i<nfiles; i++, tfid++) {
2521 * Get volume/vnode for the fetched file; caller's rights to it
2525 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2526 DONTCHECK, &parentwhentargetnotdir, &client,
2527 READ_LOCK, &rights, &anyrights)))
2528 goto Bad_BulkStatus;
2529 /* set volume synchronization information, but only once per call */
2531 SetVolumeSync(Sync, volptr);
2533 /* Are we allowed to fetch Fid's status? */
2534 if (targetptr->disk.type != vDirectory) {
2535 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2536 CHK_FETCHSTATUS, 0))) {
2537 if (rx_GetCallAbortCode(acall) == errorCode)
2538 rx_SetCallAbortCode(acall, 0);
2539 goto Bad_BulkStatus;
2543 /* set OutStatus From the Fid */
2544 GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2545 rights, anyrights, parentwhentargetnotdir);
2547 /* If a r/w volume, also set the CallBack state */
2548 if (VolumeWriteable(volptr))
2549 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2550 &CallBacks->AFSCBs_val[i]);
2552 struct AFSFid myFid;
2553 memset(&myFid, 0, sizeof(struct AFSFid));
2554 myFid.Volume = tfid->Volume;
2555 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2556 &CallBacks->AFSCBs_val[i]);
2559 /* put back the file ID and volume */
2560 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2561 parentwhentargetnotdir = (Vnode *) 0;
2562 targetptr = (Vnode *) 0;
2563 volptr = (Volume *) 0;
2567 /* Update and store volume/vnode and parent vnodes back */
2568 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2569 CallPostamble(tcon);
2571 #if FS_STATS_DETAILED
2572 TM_GetTimeOfDay(&opStopTime, 0);
2573 if (errorCode == 0) {
2575 (opP->numSuccesses)++;
2576 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2577 fs_stats_AddTo((opP->sumTime), elapsedTime);
2578 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2579 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2580 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2582 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2583 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2588 #endif /* FS_STATS_DETAILED */
2591 ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode));
2592 osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2595 } /*SRXAFS_BulkStatus*/
2598 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2599 struct AFSCBFids *Fids,
2600 struct AFSBulkStats *OutStats,
2601 struct AFSCBs *CallBacks,
2602 struct AFSVolSync *Sync)
2606 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2607 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2608 int errorCode = 0; /* return code to caller */
2609 Volume * volptr = 0; /* pointer to the volume */
2610 struct client *client; /* pointer to the client data */
2611 afs_int32 rights, anyrights; /* rights for this and any user */
2612 register struct AFSFid *tfid; /* file id we're dealing with now */
2613 struct rx_connection *tcon;
2614 AFSFetchStatus *tstatus;
2615 #if FS_STATS_DETAILED
2616 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2617 struct timeval opStartTime,
2618 opStopTime; /* Start/stop times for RPC op*/
2619 struct timeval elapsedTime; /* Transfer time */
2622 * Set our stats pointer, remember when the RPC operation started, and
2623 * tally the operation.
2625 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2629 TM_GetTimeOfDay(&opStartTime, 0);
2630 #endif /* FS_STATS_DETAILED */
2632 ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2634 AFSCallStats.TotalCalls++;
2637 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2638 if (nfiles <= 0) { /* Sanity check */
2640 goto Audit_and_Return;
2643 /* allocate space for return output parameters */
2644 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2645 malloc(nfiles * sizeof(struct AFSFetchStatus));
2646 OutStats->AFSBulkStats_len = nfiles;
2647 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2648 malloc(nfiles * sizeof(struct AFSCallBack));
2649 CallBacks->AFSCBs_len = nfiles;
2651 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2652 goto Bad_InlineBulkStatus;
2655 tfid = Fids->AFSCBFids_val;
2656 for (i=0; i<nfiles; i++, tfid++) {
2658 * Get volume/vnode for the fetched file; caller's rights to it
2662 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2663 DONTCHECK, &parentwhentargetnotdir, &client,
2664 READ_LOCK, &rights, &anyrights))) {
2665 tstatus = &OutStats->AFSBulkStats_val[i];
2666 tstatus->errorCode = errorCode;
2667 parentwhentargetnotdir = (Vnode *) 0;
2668 targetptr = (Vnode *) 0;
2669 volptr = (Volume *) 0;
2673 /* set volume synchronization information, but only once per call */
2675 SetVolumeSync(Sync, volptr);
2677 /* Are we allowed to fetch Fid's status? */
2678 if (targetptr->disk.type != vDirectory) {
2679 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2680 CHK_FETCHSTATUS, 0))) {
2681 tstatus = &OutStats->AFSBulkStats_val[i];
2682 tstatus->errorCode = errorCode;
2683 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2684 parentwhentargetnotdir = (Vnode *) 0;
2685 targetptr = (Vnode *) 0;
2686 volptr = (Volume *) 0;
2691 /* set OutStatus From the Fid */
2692 GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i],
2693 rights, anyrights, parentwhentargetnotdir);
2695 /* If a r/w volume, also set the CallBack state */
2696 if (VolumeWriteable(volptr))
2697 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2698 &CallBacks->AFSCBs_val[i]);
2700 struct AFSFid myFid;
2701 memset(&myFid, 0, sizeof(struct AFSFid));
2702 myFid.Volume = tfid->Volume;
2703 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2704 &CallBacks->AFSCBs_val[i]);
2707 /* put back the file ID and volume */
2708 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2709 parentwhentargetnotdir = (Vnode *) 0;
2710 targetptr = (Vnode *) 0;
2711 volptr = (Volume *) 0;
2714 Bad_InlineBulkStatus:
2715 /* Update and store volume/vnode and parent vnodes back */
2716 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2717 CallPostamble(tcon);
2719 #if FS_STATS_DETAILED
2720 TM_GetTimeOfDay(&opStopTime, 0);
2721 if (errorCode == 0) {
2723 (opP->numSuccesses)++;
2724 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2725 fs_stats_AddTo((opP->sumTime), elapsedTime);
2726 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2727 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2728 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2730 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2731 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2736 #endif /* FS_STATS_DETAILED */
2739 ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode));
2740 osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2743 } /*SRXAFS_InlineBulkStatus*/
2746 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,
2748 struct AFSFetchStatus *OutStatus,
2749 struct AFSCallBack *CallBack,
2750 struct AFSVolSync *Sync)
2753 struct rx_connection *tcon;
2754 #if FS_STATS_DETAILED
2755 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2756 struct timeval opStartTime,
2757 opStopTime; /* Start/stop times for RPC op*/
2758 struct timeval elapsedTime; /* Transfer time */
2761 * Set our stats pointer, remember when the RPC operation started, and
2762 * tally the operation.
2764 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2768 TM_GetTimeOfDay(&opStartTime, 0);
2769 #endif /* FS_STATS_DETAILED */
2771 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2772 goto Bad_FetchStatus;
2774 code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2777 CallPostamble(tcon);
2779 #if FS_STATS_DETAILED
2780 TM_GetTimeOfDay(&opStopTime, 0);
2783 (opP->numSuccesses)++;
2784 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2785 fs_stats_AddTo((opP->sumTime), elapsedTime);
2786 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2787 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2788 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2790 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2791 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2796 #endif /* FS_STATS_DETAILED */
2798 osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2801 } /*SRXAFS_FetchStatus*/
2804 afs_int32 common_StoreData64 (struct rx_call *acall,
2806 struct AFSStoreStatus *InStatus,
2809 afs_offs_t FileLength,
2810 struct AFSFetchStatus *OutStatus,
2811 struct AFSVolSync *Sync)
2813 Vnode * targetptr = 0; /* pointer to input fid */
2814 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2815 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2816 int errorCode = 0; /* return code for caller */
2817 int fileCode = 0; /* return code from vol package */
2818 Volume * volptr = 0; /* pointer to the volume header */
2819 struct client * client; /* pointer to client structure */
2820 afs_int32 rights, anyrights; /* rights for this and any user */
2821 struct client *t_client; /* tmp ptr to client data */
2822 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2823 struct rx_connection *tcon;
2824 #if FS_STATS_DETAILED
2825 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2826 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2827 struct timeval opStartTime,
2828 opStopTime; /* Start/stop times for RPC op*/
2829 struct timeval xferStartTime,
2830 xferStopTime; /* Start/stop times for xfer portion*/
2831 struct timeval elapsedTime; /* Transfer time */
2832 afs_size_t bytesToXfer; /* # bytes to xfer */
2833 afs_size_t bytesXferred; /* # bytes actually xfer */
2834 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2837 * Set our stats pointers, remember when the RPC operation started, and
2838 * tally the operation.
2840 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2841 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2846 ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2847 Fid->Volume, Fid->Vnode, Fid->Unique));
2848 TM_GetTimeOfDay(&opStartTime, 0);
2849 #endif /* FS_STATS_DETAILED */
2852 AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2855 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2858 /* Get ptr to client data for user Id for logging */
2859 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2860 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2861 ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2862 Fid->Volume, Fid->Vnode, Fid->Unique,
2863 inet_ntoa(logHostAddr), t_client->ViceId));
2864 #ifdef AFS_LARGEFILE_ENV
2865 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",
2866 Fid->Volume, Fid->Vnode, Fid->Unique,
2867 inet_ntoa(logHostAddr), t_client->ViceId,
2868 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
2869 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff),
2870 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff)));
2871 #else /* !AFS_LARGEFILE_ENV */
2872 ViceLog(25, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d, Pos 0X%x, Len 0X%x, FileLen 0X%x\n",
2873 Fid->Volume, Fid->Vnode, Fid->Unique,
2874 inet_ntoa(logHostAddr), t_client->ViceId,
2878 #endif /* !AFS_LARGEFILE_ENV */
2882 * Get associated volume/vnode for the stored file; caller's rights
2885 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2886 MustNOTBeDIR, &parentwhentargetnotdir,
2887 &client, WRITE_LOCK, &rights, &anyrights))) {
2891 /* set volume synchronization information */
2892 SetVolumeSync(Sync, volptr);
2894 if ((targetptr->disk.type == vSymlink)) {
2895 /* Should we return a better error code here??? */
2900 /* Check if we're allowed to store the data */
2901 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2902 CHK_STOREDATA, InStatus))) {
2907 * Drop the read lock on the parent directory after saving the parent
2908 * vnode information we need to pass to GetStatus
2910 if (parentwhentargetnotdir != NULL) {
2911 tparentwhentargetnotdir = *parentwhentargetnotdir;
2912 VPutVnode(&fileCode, parentwhentargetnotdir);
2913 assert(!fileCode || (fileCode == VSALVAGE));
2914 parentwhentargetnotdir = NULL;
2919 #if FS_STATS_DETAILED
2921 * Remember when the data transfer started.
2923 TM_GetTimeOfDay(&xferStartTime, 0);
2924 #endif /* FS_STATS_DETAILED */
2926 /* Do the actual storing of the data */
2927 #if FS_STATS_DETAILED
2928 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2929 (afs_size_t) Pos, (afs_size_t) Length,
2930 (afs_size_t) FileLength,
2931 (InStatus->Mask & AFS_FSYNC),
2932 &bytesToXfer, &bytesXferred);
2934 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2936 (afs_size_t) Pos, (afs_size_t) Length,
2937 (afs_size_t) FileLength,
2938 (InStatus->Mask & AFS_FSYNC));
2939 if (errorCode && (!targetptr->changed_newTime))
2941 #endif /* FS_STATS_DETAILED */
2942 #if FS_STATS_DETAILED
2944 * At this point, the data transfer is done, for good or ill. Remember
2945 * when the transfer ended, bump the number of successes/failures, and
2946 * integrate the transfer size and elapsed time into the stats. If the
2947 * operation failed, we jump to the appropriate point.
2949 TM_GetTimeOfDay(&xferStopTime, 0);
2951 (xferP->numXfers)++;
2953 (xferP->numSuccesses)++;
2956 * Bump the xfer sum by the number of bytes actually sent, NOT the
2959 tot_bytesXferred += bytesXferred;
2960 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2961 tot_bytesXferred &= 0x3FF;
2962 if (bytesXferred < xferP->minBytes)
2963 xferP->minBytes = bytesXferred;
2964 if (bytesXferred > xferP->maxBytes)
2965 xferP->maxBytes = bytesXferred;
2968 * Tally the size of the object. Note: we tally the actual size,
2969 * NOT the number of bytes that made it out over the wire.
2971 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2972 (xferP->count[0])++;
2974 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2975 (xferP->count[1])++;
2977 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2978 (xferP->count[2])++;
2980 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2981 (xferP->count[3])++;
2983 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2984 (xferP->count[4])++;
2986 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2987 (xferP->count[5])++;
2989 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2990 (xferP->count[6])++;
2992 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2993 (xferP->count[7])++;
2995 (xferP->count[8])++;
2997 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2998 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2999 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3000 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3001 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3003 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3004 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3010 * Finally, go off to tell our caller the bad news in case the
3013 if (errorCode && (!targetptr->changed_newTime))
3015 #endif /* FS_STATS_DETAILED */
3017 /* Update the status of the target's vnode */
3018 Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
3019 volptr, (afs_size_t) 0);
3021 /* Get the updated File's status back to the caller */
3022 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
3025 /* Update and store volume/vnode and parent vnodes back */
3026 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3027 ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3029 CallPostamble(tcon);
3031 #if FS_STATS_DETAILED
3032 TM_GetTimeOfDay(&opStopTime, 0);
3033 if (errorCode == 0) {
3035 (opP->numSuccesses)++;
3036 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3037 fs_stats_AddTo((opP->sumTime), elapsedTime);
3038 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3039 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3040 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3042 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3043 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3047 #endif /* FS_STATS_DETAILED */
3049 osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
3052 } /*common_StoreData64*/
3054 afs_int32 SRXAFS_StoreData (struct rx_call *acall,
3056 struct AFSStoreStatus *InStatus,
3059 afs_uint32 FileLength,
3060 struct AFSFetchStatus *OutStatus,
3061 struct AFSVolSync *Sync)
3065 code = common_StoreData64 (acall, Fid, InStatus, Pos, Length, FileLength,
3069 } /*SRXAFS_StoreData*/
3071 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,
3073 struct AFSStoreStatus *InStatus,
3076 afs_uint64 FileLength,
3077 struct AFSFetchStatus *OutStatus,
3078 struct AFSVolSync *Sync)
3083 afs_offs_t tFileLength;
3085 #ifdef AFS_64BIT_ENV
3086 #ifndef AFS_LARGEFILE_ENV
3087 if (FileLength > 0x7fffffff)
3089 #endif /* !AFS_LARGEFILE_ENV */
3092 tFileLength = FileLength;
3093 #else /* AFS_64BIT_ENV */
3094 if (FileLength.high)
3097 tLength = Length.low;
3098 tFileLength = FileLength.low;
3099 #endif /* AFS_64BIT_ENV */
3101 code = common_StoreData64 (acall, Fid, InStatus, tPos, tLength, tFileLength,
3106 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,
3108 struct AFSOpaque *AccessList,
3109 struct AFSFetchStatus *OutStatus,
3110 struct AFSVolSync *Sync)
3112 Vnode * targetptr = 0; /* pointer to input fid */
3113 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3114 int errorCode = 0; /* return code for caller */
3115 struct AFSStoreStatus InStatus; /* Input status for fid */
3116 Volume * volptr = 0; /* pointer to the volume header */
3117 struct client * client; /* pointer to client structure */
3118 afs_int32 rights, anyrights; /* rights for this and any user */
3119 struct rx_connection *tcon;
3120 struct client *t_client; /* tmp ptr to client data */
3121 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3122 #if FS_STATS_DETAILED
3123 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3124 struct timeval opStartTime,
3125 opStopTime; /* Start/stop times for RPC op*/
3126 struct timeval elapsedTime; /* Transfer time */
3129 * Set our stats pointer, remember when the RPC operation started, and
3130 * tally the operation.
3132 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3136 TM_GetTimeOfDay(&opStartTime, 0);
3137 #endif /* FS_STATS_DETAILED */
3138 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3141 /* Get ptr to client data for user Id for logging */
3142 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3143 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3144 ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3145 Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3146 inet_ntoa(logHostAddr), t_client->ViceId));
3148 AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3151 InStatus.Mask = 0; /* not storing any status */
3154 * Get associated volume/vnode for the target dir; caller's rights
3155 * are also returned.
3157 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3158 MustBeDIR, &parentwhentargetnotdir,
3159 &client, WRITE_LOCK, &rights, &anyrights))) {
3163 /* set volume synchronization information */
3164 SetVolumeSync(Sync, volptr);
3166 /* Check if we have permission to change the dir's ACL */
3167 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3168 CHK_STOREACL, &InStatus))) {
3172 /* Build and store the new Access List for the dir */
3173 if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3177 targetptr->changed_newTime = 1; /* status change of directory */
3179 /* convert the write lock to a read lock before breaking callbacks */
3180 VVnodeWriteToRead(&errorCode, targetptr);
3181 assert(!errorCode || errorCode == VSALVAGE);
3183 /* break call backs on the directory */
3184 BreakCallBack(client->host, Fid, 0);
3186 /* Get the updated dir's status back to the caller */
3187 GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3190 /* Update and store volume/vnode and parent vnodes back */
3191 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3192 ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3193 CallPostamble(tcon);
3195 #if FS_STATS_DETAILED
3196 TM_GetTimeOfDay(&opStopTime, 0);
3197 if (errorCode == 0) {
3199 (opP->numSuccesses)++;
3200 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3201 fs_stats_AddTo((opP->sumTime), elapsedTime);
3202 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3203 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3204 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3206 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3207 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3211 #endif /* FS_STATS_DETAILED */
3213 osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3216 } /*SRXAFS_StoreACL*/
3220 * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3221 * should be merged when possible.
3224 SAFSS_StoreStatus (struct rx_call *acall,
3226 struct AFSStoreStatus *InStatus,
3227 struct AFSFetchStatus *OutStatus,
3228 struct AFSVolSync *Sync)
3231 Vnode * targetptr = 0; /* pointer to input fid */
3232 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3233 int errorCode = 0; /* return code for caller */
3234 Volume * volptr = 0; /* pointer to the volume header */
3235 struct client * client; /* pointer to client structure */
3236 afs_int32 rights, anyrights; /* rights for this and any user */
3237 struct client *t_client; /* tmp ptr to client data */
3238 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3239 struct rx_connection *tcon = rx_ConnectionOf(acall);
3241 /* Get ptr to client data for user Id for logging */
3242 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3243 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3244 ViceLog(1, ("SAFS_StoreStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
3245 Fid->Volume, Fid->Vnode, Fid->Unique,
3246 inet_ntoa(logHostAddr), t_client->ViceId));
3248 AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3251 * Get volume/vnode for the target file; caller's rights to it are
3254 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3255 DONTCHECK, &parentwhentargetnotdir,
3256 &client, WRITE_LOCK, &rights, &anyrights))) {
3257 goto Bad_StoreStatus;
3260 /* set volume synchronization information */
3261 SetVolumeSync(Sync, volptr);
3263 /* Check if the caller has proper permissions to store status to Fid */
3264 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3265 CHK_STORESTATUS, InStatus))) {
3266 goto Bad_StoreStatus;
3269 * Check for a symbolic link; we can't chmod these (otherwise could
3270 * change a symlink to a mt pt or vice versa)
3272 if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3274 goto Bad_StoreStatus;
3277 /* Update the status of the target's vnode */
3278 Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3279 (parentwhentargetnotdir ?
3280 parentwhentargetnotdir : targetptr), volptr,
3283 /* convert the write lock to a read lock before breaking callbacks */
3284 VVnodeWriteToRead(&errorCode, targetptr);
3285 assert(!errorCode || errorCode == VSALVAGE);
3287 /* Break call backs on Fid */
3288 BreakCallBack(client->host, Fid, 0);
3290 /* Return the updated status back to caller */
3291 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3294 /* Update and store volume/vnode and parent vnodes back */
3295 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3296 ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3299 } /*SAFSS_StoreStatus*/
3302 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,
3304 struct AFSStoreStatus *InStatus,
3305 struct AFSFetchStatus *OutStatus,
3306 struct AFSVolSync *Sync)
3309 struct rx_connection *tcon;
3310 #if FS_STATS_DETAILED
3311 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3312 struct timeval opStartTime,
3313 opStopTime; /* Start/stop times for RPC op*/
3314 struct timeval elapsedTime; /* Transfer time */
3317 * Set our stats pointer, remember when the RPC operation started, and
3318 * tally the operation.
3320 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3324 TM_GetTimeOfDay(&opStartTime, 0);
3325 #endif /* FS_STATS_DETAILED */
3327 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3328 goto Bad_StoreStatus;
3330 code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3333 CallPostamble(tcon);
3335 #if FS_STATS_DETAILED
3336 TM_GetTimeOfDay(&opStopTime, 0);
3339 (opP->numSuccesses)++;
3340 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3341 fs_stats_AddTo((opP->sumTime), elapsedTime);
3342 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3343 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3344 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3346 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3347 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3352 #endif /* FS_STATS_DETAILED */
3354 osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3357 } /*SRXAFS_StoreStatus*/
3361 * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3362 * merged in when possible.
3365 SAFSS_RemoveFile (struct rx_call *acall,
3366 struct AFSFid *DirFid,
3368 struct AFSFetchStatus *OutDirStatus,
3369 struct AFSVolSync *Sync)
3371 Vnode * parentptr = 0; /* vnode of input Directory */
3372 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3373 Vnode * targetptr = 0; /* file to be deleted */
3374 Volume * volptr = 0; /* pointer to the volume header */
3375 AFSFid fileFid; /* area for Fid from the directory */
3376 int errorCode = 0; /* error code */
3377 DirHandle dir; /* Handle for dir package I/O */
3378 struct client * client; /* pointer to client structure */
3379 afs_int32 rights, anyrights; /* rights for this and any user */
3380 struct client *t_client; /* tmp ptr to client data */
3381 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3382 struct rx_connection *tcon = rx_ConnectionOf(acall);
3385 /* Get ptr to client data for user Id for logging */
3386 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3387 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3388 ViceLog(1, ("SAFS_RemoveFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3389 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3390 inet_ntoa(logHostAddr), t_client->ViceId));
3392 AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3395 * Get volume/vnode for the parent dir; caller's access rights are
3398 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3399 MustBeDIR, &parentwhentargetnotdir,
3400 &client, WRITE_LOCK, &rights, &anyrights))) {
3401 goto Bad_RemoveFile;
3403 /* set volume synchronization information */
3404 SetVolumeSync(Sync, volptr);
3406 /* Does the caller has delete (& write) access to the parent directory? */
3407 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3408 goto Bad_RemoveFile;
3411 /* Actually delete the desired file */
3412 if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3413 &fileFid, Name, MustNOTBeDIR))) {
3414 goto Bad_RemoveFile;
3417 /* Update the vnode status of the parent dir */
3418 #if FS_STATS_DETAILED
3419 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3420 parentptr->disk.linkCount, client->InSameNetwork);
3422 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3423 parentptr->disk.linkCount);
3424 #endif /* FS_STATS_DETAILED */
3426 /* Return the updated parent dir's status back to caller */
3427 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3429 /* Handle internal callback state for the parent and the deleted file */
3430 if (targetptr->disk.linkCount == 0) {
3431 /* no references left, discard entry */
3432 DeleteFileCallBacks(&fileFid);
3433 /* convert the parent lock to a read lock before breaking callbacks */
3434 VVnodeWriteToRead(&errorCode, parentptr);
3435 assert(!errorCode || errorCode == VSALVAGE);
3437 /* convert the parent lock to a read lock before breaking callbacks */
3438 VVnodeWriteToRead(&errorCode, parentptr);
3439 assert(!errorCode || errorCode == VSALVAGE);
3440 /* convert the target lock to a read lock before breaking callbacks */
3441 VVnodeWriteToRead(&errorCode, targetptr);
3442 assert(!errorCode || errorCode == VSALVAGE);
3443 /* tell all the file has changed */
3444 BreakCallBack(client->host, &fileFid, 1);
3447 /* break call back on the directory */
3448 BreakCallBack(client->host, DirFid, 0);
3451 /* Update and store volume/vnode and parent vnodes back */
3452 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3454 ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode));
3457 } /*SAFSS_RemoveFile*/
3460 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3461 struct AFSFid *DirFid,
3463 struct AFSFetchStatus *OutDirStatus,
3464 struct AFSVolSync *Sync)
3467 struct rx_connection *tcon;
3468 #if FS_STATS_DETAILED
3469 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3470 struct timeval opStartTime,
3471 opStopTime; /* Start/stop times for RPC op*/
3472 struct timeval elapsedTime; /* Transfer time */
3475 * Set our stats pointer, remember when the RPC operation started, and
3476 * tally the operation.
3478 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3482 TM_GetTimeOfDay(&opStartTime, 0);
3483 #endif /* FS_STATS_DETAILED */
3485 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3486 goto Bad_RemoveFile;
3488 code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3491 CallPostamble(tcon);
3493 #if FS_STATS_DETAILED
3494 TM_GetTimeOfDay(&opStopTime, 0);
3497 (opP->numSuccesses)++;
3498 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3499 fs_stats_AddTo((opP->sumTime), elapsedTime);
3500 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3501 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3502 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3504 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3505 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3510 #endif /* FS_STATS_DETAILED */
3512 osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3515 } /*SRXAFS_RemoveFile*/
3519 * This routine is called exclusively from SRXAFS_CreateFile(), and should
3520 * be merged in when possible.
3523 SAFSS_CreateFile (struct rx_call *acall,
3524 struct AFSFid *DirFid,
3526 struct AFSStoreStatus *InStatus,
3527 struct AFSFid *OutFid,
3528 struct AFSFetchStatus *OutFidStatus,
3529 struct AFSFetchStatus *OutDirStatus,
3530 struct AFSCallBack *CallBack,
3531 struct AFSVolSync *Sync)
3533 Vnode * parentptr = 0; /* vnode of input Directory */
3534 Vnode * targetptr = 0; /* vnode of the new file */
3535 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3536 Volume * volptr = 0; /* pointer to the volume header */
3537 int errorCode = 0; /* error code */
3538 DirHandle dir; /* Handle for dir package I/O */
3539 struct client * client; /* pointer to client structure */
3540 afs_int32 rights, anyrights; /* rights for this and any user */
3541 struct client *t_client; /* tmp ptr to client data */
3542 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3543 struct rx_connection *tcon = rx_ConnectionOf(acall);
3547 /* Get ptr to client data for user Id for logging */
3548 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3549 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3550 ViceLog(1, ("SAFS_CreateFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3551 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3552 inet_ntoa(logHostAddr), t_client->ViceId));
3554 AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3556 if (!FileNameOK(Name)) {
3558 goto Bad_CreateFile;
3562 * Get associated volume/vnode for the parent dir; caller long are
3565 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3566 MustBeDIR, &parentwhentargetnotdir,
3567 &client, WRITE_LOCK, &rights, &anyrights))) {
3568 goto Bad_CreateFile;
3571 /* set volume synchronization information */
3572 SetVolumeSync(Sync, volptr);
3574 /* Can we write (and insert) onto the parent directory? */
3575 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3576 goto Bad_CreateFile;
3578 /* get a new vnode for the file to be created and set it up */
3579 if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3580 Name, OutFid, vFile, nBlocks(0)))) {
3581 goto Bad_CreateFile;
3584 /* update the status of the parent vnode */
3585 #if FS_STATS_DETAILED
3586 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3587 parentptr->disk.linkCount, client->InSameNetwork);
3589 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3590 parentptr->disk.linkCount);
3591 #endif /* FS_STATS_DETAILED */
3593 /* update the status of the new file's vnode */
3594 Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3595 parentptr, volptr, (afs_size_t)0);
3597 /* set up the return status for the parent dir and the newly created file */
3598 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3599 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3601 /* convert the write lock to a read lock before breaking callbacks */
3602 VVnodeWriteToRead(&errorCode, parentptr);
3603 assert(!errorCode || errorCode == VSALVAGE);
3605 /* break call back on parent dir */
3606 BreakCallBack(client->host, DirFid, 0);
3608 /* Return a callback promise for the newly created file to the caller */
3609 SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3612 /* Update and store volume/vnode and parent vnodes back */
3613 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3615 ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode));
3618 } /*SAFSS_CreateFile*/
3621 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3622 struct AFSFid *DirFid,
3624 struct AFSStoreStatus *InStatus,
3625 struct AFSFid *OutFid,
3626 struct AFSFetchStatus *OutFidStatus,
3627 struct AFSFetchStatus *OutDirStatus,
3628 struct AFSCallBack *CallBack,
3629 struct AFSVolSync *Sync)
3632 struct rx_connection *tcon;
3633 #if FS_STATS_DETAILED
3634 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3635 struct timeval opStartTime,
3636 opStopTime; /* Start/stop times for RPC op*/
3637 struct timeval elapsedTime; /* Transfer time */
3640 * Set our stats pointer, remember when the RPC operation started, and
3641 * tally the operation.
3643 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3647 TM_GetTimeOfDay(&opStartTime, 0);
3648 #endif /* FS_STATS_DETAILED */
3650 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3651 goto Bad_CreateFile;
3653 code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3654 OutFidStatus, OutDirStatus, CallBack, Sync);
3657 CallPostamble(tcon);
3659 #if FS_STATS_DETAILED
3660 TM_GetTimeOfDay(&opStopTime, 0);
3663 (opP->numSuccesses)++;
3664 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3665 fs_stats_AddTo((opP->sumTime), elapsedTime);
3666 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3667 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3668 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3670 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3671 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3675 #endif /* FS_STATS_DETAILED */
3677 osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3680 } /*SRXAFS_CreateFile*/
3684 * This routine is called exclusively from SRXAFS_Rename(), and should be
3685 * merged in when possible.
3688 SAFSS_Rename (struct rx_call *acall,
3689 struct AFSFid *OldDirFid,
3691 struct AFSFid *NewDirFid,
3693 struct AFSFetchStatus *OutOldDirStatus,
3694 struct AFSFetchStatus *OutNewDirStatus,
3695 struct AFSVolSync *Sync)
3697 Vnode * oldvptr = 0; /* vnode of the old Directory */
3698 Vnode * newvptr = 0; /* vnode of the new Directory */
3699 Vnode * fileptr = 0; /* vnode of the file to move */
3700 Vnode * newfileptr = 0; /* vnode of the file to delete */
3701 Vnode * testvptr = 0; /* used in directory tree walk */
3702 Vnode * parent = 0; /* parent for use in SetAccessList */
3703 int errorCode = 0; /* error code */
3704 int fileCode = 0; /* used when writing Vnodes */
3705 VnodeId testnode; /* used in directory tree walk */
3706 AFSFid fileFid; /* Fid of file to move */
3707 AFSFid newFileFid; /* Fid of new file */
3708 DirHandle olddir; /* Handle for dir package I/O */
3709 DirHandle newdir; /* Handle for dir package I/O */
3710 DirHandle filedir; /* Handle for dir package I/O */
3711 DirHandle newfiledir; /* Handle for dir package I/O */
3712 Volume * volptr = 0; /* pointer to the volume header */
3713 struct client * client; /* pointer to client structure */
3714 afs_int32 rights, anyrights; /* rights for this and any user */
3715 afs_int32 newrights; /* rights for this user */
3716 afs_int32 newanyrights; /* rights for any user */
3717 int doDelete; /* deleted the rename target (ref count now 0) */
3719 struct client *t_client; /* tmp ptr to client data */
3720 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3721 struct rx_connection *tcon = rx_ConnectionOf(acall);
3726 FidZero(&newfiledir);
3728 /* Get ptr to client data for user Id for logging */
3729 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3730 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3731 ViceLog(1, ("SAFS_Rename %s to %s, Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3732 OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3733 OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3735 inet_ntoa(logHostAddr), t_client->ViceId));
3737 AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3739 if (!FileNameOK(NewName)) {
3743 if (OldDirFid->Volume != NewDirFid->Volume) {
3748 if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3749 (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) ||
3750 (strlen(NewName) == 0) || (strlen(OldName) == 0) ) {
3756 if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3757 if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3758 &oldvptr, MustBeDIR, &parent,
3759 &client, WRITE_LOCK, &rights,
3764 if (OldDirFid->Vnode == NewDirFid->Vnode) {
3766 newrights = rights, newanyrights = anyrights;
3769 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3770 &newvptr, MustBeDIR, &parent,
3771 &client, WRITE_LOCK, &newrights,
3778 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3779 &newvptr, MustBeDIR, &parent,
3780 &client, WRITE_LOCK, &newrights,
3785 if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3786 MustBeDIR, &parent, &client, WRITE_LOCK,
3787 &rights, &anyrights))) {
3793 /* set volume synchronization information */
3794 SetVolumeSync(Sync, volptr);
3796 if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3799 if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3803 /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3804 * call to CopyOnWrite returns error, it is not necessary to revert back
3805 * the effects of the first call because the contents of the volume is
3806 * not modified, it is only replicated.
3808 if (oldvptr->disk.cloned)
3810 ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n"));
3811 if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3814 SetDirHandle(&olddir, oldvptr);
3815 if (newvptr->disk.cloned)
3817 ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n"));
3818 if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3822 SetDirHandle(&newdir, newvptr);
3824 /* Lookup the file to delete its vnode */
3825 if (Lookup(&olddir, OldName, &fileFid)) {
3829 if (fileFid.Vnode == oldvptr->vnodeNumber ||
3830 fileFid.Vnode == newvptr->vnodeNumber) {
3831 errorCode = FSERR_ELOOP;
3834 fileFid.Volume = V_id(volptr);
3835 fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3836 if (errorCode != 0) {
3837 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3838 VTakeOffline (volptr);
3841 if (fileptr->disk.uniquifier != fileFid.Unique) {
3842 ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3843 VTakeOffline (volptr);
3848 if (fileptr->disk.type != vDirectory &&
3849 oldvptr != newvptr &&
3850 fileptr->disk.linkCount != 1) {
3852 * Hard links exist to this file - cannot move one of the links to
3853 * a new directory because of AFS restrictions (this is the same
3854 * reason that links cannot be made across directories, i.e.
3861 /* Lookup the new file */
3862 if (!(Lookup(&newdir, NewName, &newFileFid))) {
3863 if (readonlyServer) {
3864 errorCode = VREADONLY;
3867 if (!(newrights & PRSFS_DELETE)) {
3871 if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3872 newFileFid.Vnode == newvptr->vnodeNumber ||
3873 newFileFid.Vnode == fileFid.Vnode) {
3877 newFileFid.Volume = V_id(volptr);
3878 newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3879 if (errorCode != 0) {
3880 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3881 VTakeOffline (volptr);
3884 if (fileptr->disk.uniquifier != fileFid.Unique) {
3885 ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3886 VTakeOffline (volptr);
3890 SetDirHandle(&newfiledir, newfileptr);
3891 /* Now check that we're moving directories over directories properly, etc.
3892 * return proper POSIX error codes:
3893 * if fileptr is a file and new is a dir: EISDIR.
3894 * if fileptr is a dir and new is a file: ENOTDIR.
3895 * Also, dir to be removed must be empty, of course.
3897 if (newfileptr->disk.type == vDirectory) {
3898 if (fileptr->disk.type != vDirectory) {
3902 if ((IsEmpty(&newfiledir))) {
3908 if (fileptr->disk.type == vDirectory) {
3909 errorCode = ENOTDIR;
3916 * ok - now we check that the old name is not above new name in the
3917 * directory structure. This is to prevent removing a subtree alltogether
3919 if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3920 for (testnode = newvptr->disk.parent; testnode != 0;) {
3921 if (testnode == oldvptr->vnodeNumber) {
3922 testnode = oldvptr->disk.parent;
3925 if ((testnode == fileptr->vnodeNumber) ||
3926 (testnode == newvptr->vnodeNumber)) {
3927 errorCode = FSERR_ELOOP;
3930 if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3931 errorCode = FSERR_ELOOP;
3934 testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3935 assert(errorCode == 0);
3936 testnode = testvptr->disk.parent;
3937 VPutVnode(&errorCode, testvptr);
3938 assert(errorCode == 0);
3941 /* Do the CopyonWrite first before modifying anything else. Copying is
3942 * required because we may have to change entries for ..
3944 if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3946 ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n"));
3947 if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3951 /* If the new name exists already, delete it and the file it points to */
3954 /* Delete NewName from its directory */
3955 code = Delete(&newdir, NewName);
3958 /* Drop the link count */
3959 newfileptr->disk.linkCount--;
3960 if (newfileptr->disk.linkCount == 0) { /* Link count 0 - delete */
3962 VN_GET_LEN(newSize, newfileptr);
3963 VAdjustDiskUsage(&errorCode, volptr,
3964 -nBlocks(newSize), (afs_size_t) 0);
3965 if (VN_GET_INO(newfileptr)) {
3966 IH_REALLYCLOSE(newfileptr->handle);
3967 errorCode = IH_DEC(V_linkHandle(volptr),
3968 VN_GET_INO(newfileptr),
3969 V_parentId(volptr));
3970 IH_RELEASE(newfileptr->handle);
3971 if (errorCode == -1) {
3972 ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
3973 PrintInode(NULL, VN_GET_INO(newfileptr)),
3975 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
3976 ViceLog(0, ("Do we need to fsck?"));
3979 VN_SET_INO(newfileptr, (Inode)0);
3980 newfileptr->delete = 1; /* Mark NewName vnode to delete */
3983 /* Link count did not drop to zero.
3984 * Mark NewName vnode as changed - updates stime.
3986 newfileptr->changed_newTime = 1;
3991 * If the create below fails, and the delete above worked, we have
3992 * removed the new name and not replaced it. This is not very likely,
3993 * but possible. We could try to put the old file back, but it is
3994 * highly unlikely that it would work since it would involve issuing
3997 if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
4000 /* Delete the old name */
4001 assert(Delete(&olddir,(char *) OldName) == 0);
4003 /* if the directory length changes, reflect it in the statistics */
4004 #if FS_STATS_DETAILED
4005 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4006 oldvptr->disk.linkCount, client->InSameNetwork);
4007 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4008 newvptr->disk.linkCount, client->InSameNetwork);
4010 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4011 oldvptr->disk.linkCount);
4012 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4013 newvptr->disk.linkCount);
4014 #endif /* FS_STATS_DETAILED */
4016 if (oldvptr == newvptr)
4017 oldvptr->disk.dataVersion--; /* Since it was bumped by 2! */
4019 fileptr->disk.parent = newvptr->vnodeNumber;
4020 fileptr->changed_newTime = 1; /* status change of moved file */
4022 /* if we are dealing with a rename of a directory */
4023 if (fileptr->disk.type == vDirectory) {
4024 assert(!fileptr->disk.cloned);
4025 SetDirHandle(&filedir, fileptr);
4026 /* fix .. to point to the correct place */
4027 Delete(&filedir, ".."); /* No assert--some directories may be bad */
4028 assert(Create(&filedir, "..", NewDirFid) == 0);
4029 fileptr->disk.dataVersion++;
4030 /* if the parent directories are different the link counts have to be */
4031 /* changed due to .. in the renamed directory */
4032 if (oldvptr != newvptr) {
4033 oldvptr->disk.linkCount--;
4034 newvptr->disk.linkCount++;
4038 /* set up return status */
4039 GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
4040 GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
4041 if (newfileptr && doDelete) {
4042 DeleteFileCallBacks(&newFileFid); /* no other references */
4047 /* convert the write locks to a read locks before breaking callbacks */
4048 VVnodeWriteToRead(&errorCode, newvptr);
4049 assert(!errorCode || errorCode == VSALVAGE);
4050 if (oldvptr != newvptr) {
4051 VVnodeWriteToRead(&errorCode, oldvptr);
4052 assert(!errorCode || errorCode == VSALVAGE);
4054 if (newfileptr && !doDelete) {
4055 /* convert the write lock to a read lock before breaking callbacks */
4056 VVnodeWriteToRead(&errorCode, newfileptr);
4057 assert(!errorCode || errorCode == VSALVAGE);
4060 /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */
4061 BreakCallBack(client->host, NewDirFid, 0);
4062 if (oldvptr != newvptr) {
4063 BreakCallBack(client->host, OldDirFid, 0);
4064 if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
4065 BreakCallBack(client->host, &fileFid, 0);
4068 /* Note: it is not necessary to break the callback */
4070 DeleteFileCallBacks(&newFileFid); /* no other references */
4072 /* other's still exist (with wrong link count) */
4073 BreakCallBack(client->host, &newFileFid, 1);
4078 VPutVnode(&fileCode, newfileptr);
4079 assert(fileCode == 0);
4081 PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
4086 FidZap(&newfiledir);
4087 ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4093 afs_int32 SRXAFS_Rename (struct rx_call *acall,
4094 struct AFSFid *OldDirFid,
4096 struct AFSFid *NewDirFid,
4098 struct AFSFetchStatus *OutOldDirStatus,
4099 struct AFSFetchStatus *OutNewDirStatus,
4100 struct AFSVolSync *Sync)
4103 struct rx_connection *tcon;
4104 #if FS_STATS_DETAILED
4105 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4106 struct timeval opStartTime,
4107 opStopTime; /* Start/stop times for RPC op*/
4108 struct timeval elapsedTime; /* Transfer time */
4111 * Set our stats pointer, remember when the RPC operation started, and
4112 * tally the operation.
4114 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4118 TM_GetTimeOfDay(&opStartTime, 0);
4119 #endif /* FS_STATS_DETAILED */
4121 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4124 code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4125 OutOldDirStatus, OutNewDirStatus, Sync);
4128 CallPostamble(tcon);
4130 #if FS_STATS_DETAILED
4131 TM_GetTimeOfDay(&opStopTime, 0);
4134 (opP->numSuccesses)++;
4135 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4136 fs_stats_AddTo((opP->sumTime), elapsedTime);
4137 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4138 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4139 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4141 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4142 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4147 #endif /* FS_STATS_DETAILED */
4149 osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
4156 * This routine is called exclusively by SRXAFS_Symlink(), and should be
4157 * merged into it when possible.
4160 SAFSS_Symlink (struct rx_call *acall,
4161 struct AFSFid *DirFid,
4164 struct AFSStoreStatus *InStatus,
4165 struct AFSFid *OutFid,
4166 struct AFSFetchStatus *OutFidStatus,
4167 struct AFSFetchStatus *OutDirStatus,
4168 struct AFSVolSync *Sync)
4171 Vnode * parentptr = 0; /* vnode of input Directory */
4172 Vnode * targetptr = 0; /* vnode of the new link */
4173 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4174 int errorCode = 0; /* error code */
4176 DirHandle dir; /* Handle for dir package I/O */
4177 Volume * volptr = 0; /* pointer to the volume header */
4178 struct client * client; /* pointer to client structure */
4179 afs_int32 rights, anyrights, fd; /* rights for this and any user */
4180 struct client *t_client; /* tmp ptr to client data */
4181 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4183 struct rx_connection *tcon = rx_ConnectionOf(acall);
4187 /* Get ptr to client data for user Id for logging */
4188 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4189 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4190 ViceLog(1, ("SAFS_Symlink %s to %s, Did = %u.%d.%d, Host %s, Id %d\n", Name,
4191 LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4192 inet_ntoa(logHostAddr), t_client->ViceId));
4194 AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
4196 if (!FileNameOK(Name)) {
4202 * Get the vnode and volume for the parent dir along with the caller's
4205 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4206 MustBeDIR, &parentwhentargetnotdir,
4207 &client, WRITE_LOCK, &rights, &anyrights))) {
4211 /* set volume synchronization information */
4212 SetVolumeSync(Sync, volptr);
4214 /* Does the caller has insert (and write) access to the parent directory? */
4215 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4220 * If we're creating a mount point (any x bits clear), we must have
4221 * administer access to the directory, too. Always allow sysadmins
4224 if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
4225 if (readonlyServer) {
4226 errorCode = VREADONLY;
4230 * We have a mountpoint, 'cause we're trying to set the Unix mode
4231 * bits to something with some x bits missing (default mode bits
4232 * if AFS_SETMODE is false is 0777)
4234 if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
4240 /* get a new vnode for the symlink and set it up */
4241 if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
4242 Name, OutFid, vSymlink,
4243 nBlocks(strlen((char *) LinkContents))))) {
4247 /* update the status of the parent vnode */
4248 #if FS_STATS_DETAILED
4249 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4250 parentptr->disk.linkCount, client->InSameNetwork);
4252 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4253 parentptr->disk.linkCount);
4254 #endif /* FS_STATS_DETAILED */
4256 /* update the status of the new symbolic link file vnode */
4257 Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
4258 volptr, (afs_size_t)strlen((char *)LinkContents));
4260 /* Write the contents of the symbolic link name into the target inode */
4261 fdP = IH_OPEN(targetptr->handle);
4262 assert(fdP != NULL);
4263 assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
4266 * Set up and return modified status for the parent dir and new symlink
4269 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4270 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4272 /* convert the write lock to a read lock before breaking callbacks */
4273 VVnodeWriteToRead(&errorCode, parentptr);
4274 assert(!errorCode || errorCode == VSALVAGE);
4276 /* break call back on the parent dir */
4277 BreakCallBack(client->host, DirFid, 0);
4280 /* Write the all modified vnodes (parent, new files) and volume back */
4281 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4283 ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
4289 afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
4290 struct AFSVolSync *Sync;
4291 struct rx_call *acall; /* Rx call */
4292 struct AFSFid *DirFid; /* Parent dir's fid */
4293 char *Name; /* File name to create */
4294 char *LinkContents; /* Contents of the new created file */
4295 struct AFSStoreStatus *InStatus; /* Input status for the new symbolic link */
4296 struct AFSFid *OutFid; /* Fid for newly created symbolic link */
4297 struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
4298 struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
4302 struct rx_connection *tcon;
4303 #if FS_STATS_DETAILED
4304 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4305 struct timeval opStartTime,
4306 opStopTime; /* Start/stop times for RPC op*/
4307 struct timeval elapsedTime; /* Transfer time */
4310 * Set our stats pointer, remember when the RPC operation started, and
4311 * tally the operation.
4313 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
4317 TM_GetTimeOfDay(&opStartTime, 0);
4318 #endif /* FS_STATS_DETAILED */
4320 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4323 code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
4324 OutFidStatus, OutDirStatus, Sync);
4327 CallPostamble(tcon);
4329 #if FS_STATS_DETAILED
4330 TM_GetTimeOfDay(&opStopTime, 0);
4333 (opP->numSuccesses)++;
4334 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4335 fs_stats_AddTo((opP->sumTime), elapsedTime);
4336 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4337 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4338 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4340 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4341 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4346 #endif /* FS_STATS_DETAILED */
4348 osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4351 } /*SRXAFS_Symlink*/
4355 * This routine is called exclusively by SRXAFS_Link(), and should be
4356 * merged into it when possible.
4359 SAFSS_Link (struct rx_call *acall,
4360 struct AFSFid *DirFid,
4362 struct AFSFid *ExistingFid,
4363 struct AFSFetchStatus *OutFidStatus,
4364 struct AFSFetchStatus *OutDirStatus,
4365 struct AFSVolSync *Sync)
4367 Vnode * parentptr = 0; /* vnode of input Directory */
4368 Vnode * targetptr = 0; /* vnode of the new file */
4369 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4370 Volume * volptr = 0; /* pointer to the volume header */
4371 int errorCode = 0; /* error code */
4372 DirHandle dir; /* Handle for dir package I/O */
4373 struct client * client; /* pointer to client structure */
4374 afs_int32 rights, anyrights; /* rights for this and any user */
4375 struct client *t_client; /* tmp ptr to client data */
4376 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4377 struct rx_connection *tcon = rx_ConnectionOf(acall);
4381 /* Get ptr to client data for user Id for logging */
4382 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4383 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4384 ViceLog(1, ("SAFS_Link %s, Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
4385 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4386 ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
4387 inet_ntoa(logHostAddr), t_client->ViceId));
4389 AFSCallStats.Link++, AFSCallStats.TotalCalls++;
4391 if (DirFid->Volume != ExistingFid->Volume) {
4395 if (!FileNameOK(Name)) {
4401 * Get the vnode and volume for the parent dir along with the caller's
4404 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4405 MustBeDIR, &parentwhentargetnotdir,
4406 &client, WRITE_LOCK, &rights, &anyrights))) {
4410 /* set volume synchronization information */
4411 SetVolumeSync(Sync, volptr);
4413 /* Can the caller insert into the parent directory? */
4414 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4418 if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
4419 (DirFid->Vnode == ExistingFid->Vnode)) { /* at present, */
4420 /* AFS fileservers always have directory vnodes that are odd. */
4425 /* get the file vnode */
4426 if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
4429 if (targetptr->disk.type != vFile) {
4433 if (targetptr->disk.parent != DirFid->Vnode) {
4437 if (parentptr->disk.cloned)
4439 ViceLog(25, ("Link : calling CopyOnWrite on target dir\n"));
4440 if ( ( errorCode = CopyOnWrite(parentptr, volptr)))
4441 goto Bad_Link; /* disk full error */
4444 /* add the name to the directory */
4445 SetDirHandle(&dir, parentptr);
4446 if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
4450 /* update the status in the parent vnode */
4451 /**WARNING** --> disk.author SHOULDN'T be modified???? */
4452 #if FS_STATS_DETAILED
4453 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4454 parentptr->disk.linkCount, client->InSameNetwork);
4456 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4457 parentptr->disk.linkCount);
4458 #endif /* FS_STATS_DETAILED */
4460 targetptr->disk.linkCount++;
4461 targetptr->disk.author = client->ViceId;
4462 targetptr->changed_newTime = 1; /* Status change of linked-to file */
4464 /* set up return status */
4465 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4466 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4468 /* convert the write locks to read locks before breaking callbacks */
4469 VVnodeWriteToRead(&errorCode, targetptr);
4470 assert(!errorCode || errorCode == VSALVAGE);
4471 VVnodeWriteToRead(&errorCode, parentptr);
4472 assert(!errorCode || errorCode == VSALVAGE);
4474 /* break call back on DirFid */
4475 BreakCallBack(client->host, DirFid, 0);
4477 * We also need to break the callback for the file that is hard-linked since part
4478 * of its status (like linkcount) is changed
4480 BreakCallBack(client->host, ExistingFid, 0);
4483 /* Write the all modified vnodes (parent, new files) and volume back */
4484 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4486 ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
4492 afs_int32 SRXAFS_Link (struct rx_call *acall,
4493 struct AFSFid *DirFid,
4495 struct AFSFid *ExistingFid,
4496 struct AFSFetchStatus *OutFidStatus,
4497 struct AFSFetchStatus *OutDirStatus,
4498 struct AFSVolSync *Sync)
4501 struct rx_connection *tcon;
4502 #if FS_STATS_DETAILED
4503 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4504 struct timeval opStartTime,
4505 opStopTime; /* Start/stop times for RPC op*/
4506 struct timeval elapsedTime; /* Transfer time */
4509 * Set our stats pointer, remember when the RPC operation started, and
4510 * tally the operation.
4512 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
4516 TM_GetTimeOfDay(&opStartTime, 0);
4517 #endif /* FS_STATS_DETAILED */
4519 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4522 code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
4523 OutDirStatus, Sync);
4526 CallPostamble(tcon);
4528 #if FS_STATS_DETAILED
4529 TM_GetTimeOfDay(&opStopTime, 0);
4532 (opP->numSuccesses)++;
4533 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4534 fs_stats_AddTo((opP->sumTime), elapsedTime);
4535 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4536 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4537 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4539 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4540 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4545 #endif /* FS_STATS_DETAILED */
4547 osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
4554 * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4555 * merged into it when possible.
4558 SAFSS_MakeDir (struct rx_call *acall,
4559 struct AFSFid *DirFid,
4561 struct AFSStoreStatus *InStatus,
4562 struct AFSFid *OutFid,
4563 struct AFSFetchStatus *OutFidStatus,
4564 struct AFSFetchStatus *OutDirStatus,
4565 struct AFSCallBack *CallBack,
4566 struct AFSVolSync *Sync)
4569 Vnode * parentptr = 0; /* vnode of input Directory */
4570 Vnode * targetptr = 0; /* vnode of the new file */
4571 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4572 Volume * volptr = 0; /* pointer to the volume header */
4573 int errorCode = 0; /* error code */
4574 struct acl_accessList * newACL; /* Access list */
4575 int newACLSize; /* Size of access list */
4576 DirHandle dir; /* Handle for dir package I/O */
4577 DirHandle parentdir; /* Handle for dir package I/O */
4578 struct client * client; /* pointer to client structure */
4579 afs_int32 rights, anyrights; /* rights for this and any user */
4580 struct client *t_client; /* tmp ptr to client data */
4581 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4582 struct rx_connection *tcon = rx_ConnectionOf(acall);
4585 FidZero(&parentdir);
4587 /* Get ptr to client data for user Id for logging */
4588 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4589 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4590 ViceLog(1, ("SAFS_MakeDir %s, Did = %u.%d.%d, Host %s, Id %d\n",
4591 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4592 inet_ntoa(logHostAddr), t_client->ViceId));
4594 AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;
4596 if (!FileNameOK(Name)) {
4602 * Get the vnode and volume for the parent dir along with the caller's
4605 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4606 MustBeDIR, &parentwhentargetnotdir,
4607 &client, WRITE_LOCK, &rights, &anyrights))) {
4611 /* set volume synchronization information */
4612 SetVolumeSync(Sync, volptr);
4614 /* Write access to the parent directory? */
4615 #ifdef DIRCREATE_NEED_WRITE
4617 * requires w access for the user to create a directory. this
4618 * closes a loophole in the current security arrangement, since a
4619 * user with i access only can create a directory and get the
4620 * implcit a access that goes with dir ownership, and proceed to
4621 * subvert quota in the volume.
4623 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
4624 (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
4626 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4627 #endif /* DIRCREATE_NEED_WRITE */
4631 #define EMPTYDIRBLOCKS 2
4632 /* get a new vnode and set it up */
4633 if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
4634 Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) {
4638 /* Update the status for the parent dir */
4639 #if FS_STATS_DETAILED
4640 Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4641 parentptr->disk.linkCount+1, client->InSameNetwork);
4643 Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4644 parentptr->disk.linkCount+1);
4645 #endif /* FS_STATS_DETAILED */
4647 /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4648 assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
4649 &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
4650 assert(parentwhentargetnotdir == 0);
4651 memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
4653 /* update the status for the target vnode */
4654 Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
4655 parentptr, volptr, (afs_size_t)0);
4657 /* Actually create the New directory in the directory package */
4658 SetDirHandle(&dir, targetptr);
4659 assert(!(MakeDir(&dir, OutFid, DirFid)));
4661 VN_SET_LEN(targetptr, (afs_size_t) Length(&dir));
4663 /* set up return status */
4664 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4665 GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4667 /* convert the write lock to a read lock before breaking callbacks */
4668 VVnodeWriteToRead(&errorCode, parentptr);
4669 assert(!errorCode || errorCode == VSALVAGE);
4671 /* break call back on DirFid */
4672 BreakCallBack(client->host, DirFid, 0);
4674 /* Return a callback promise to caller */
4675 SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
4678 /* Write the all modified vnodes (parent, new files) and volume back */
4679 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4682 ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode));
4688 afs_int32 SRXAFS_MakeDir (struct rx_call *acall,
4689 struct AFSFid *DirFid,
4691 struct AFSStoreStatus *InStatus,
4692 struct AFSFid *OutFid,
4693 struct AFSFetchStatus *OutFidStatus,
4694 struct AFSFetchStatus *OutDirStatus,
4695 struct AFSCallBack *CallBack,
4696 struct AFSVolSync *Sync)
4699 struct rx_connection *tcon;
4700 #if FS_STATS_DETAILED
4701 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4702 struct timeval opStartTime,
4703 opStopTime; /* Start/stop times for RPC op*/
4704 struct timeval elapsedTime; /* Transfer time */
4707 * Set our stats pointer, remember when the RPC operation started, and
4708 * tally the operation.
4710 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
4714 TM_GetTimeOfDay(&opStartTime, 0);
4715 #endif /* FS_STATS_DETAILED */
4716 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4719 code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
4720 OutFidStatus, OutDirStatus, CallBack, Sync);
4723 CallPostamble(tcon);
4725 #if FS_STATS_DETAILED
4726 TM_GetTimeOfDay(&opStopTime, 0);
4729 (opP->numSuccesses)++;
4730 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4731 fs_stats_AddTo((opP->sumTime), elapsedTime);
4732 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4733 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4734 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4736 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4737 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4742 #endif /* FS_STATS_DETAILED */
4744 osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4747 } /*SRXAFS_MakeDir*/
4751 * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4752 * merged into it when possible.
4755 SAFSS_RemoveDir (struct rx_call *acall,
4756 struct AFSFid *DirFid,
4758 struct AFSFetchStatus *OutDirStatus,
4759 struct AFSVolSync *Sync)
4762 Vnode * parentptr = 0; /* vnode of input Directory */
4763 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4764 Vnode * targetptr = 0; /* file to be deleted */
4765 AFSFid fileFid; /* area for Fid from the directory */
4766 int errorCode = 0; /* error code */
4767 DirHandle dir; /* Handle for dir package I/O */
4768 Volume * volptr = 0; /* pointer to the volume header */
4769 struct client * client; /* pointer to client structure */
4770 afs_int32 rights, anyrights; /* rights for this and any user */
4771 Vnode debugvnode1, debugvnode2;
4772 struct client *t_client; /* tmp ptr to client data */
4773 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4774 struct rx_connection *tcon = rx_ConnectionOf(acall);
4778 /* Get ptr to client data for user Id for logging */
4779 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4780 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4781 ViceLog(1, ("SAFS_RemoveDir %s, Did = %u.%d.%d, Host %s, Id %d\n",
4782 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4783 inet_ntoa(logHostAddr), t_client->ViceId));
4785 AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
4788 * Get the vnode and volume for the parent dir along with the caller's
4791 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4792 MustBeDIR, &parentwhentargetnotdir,
4793 &client, WRITE_LOCK, &rights, &anyrights))) {
4796 debugvnode1 = *parentptr;
4798 /* set volume synchronization information */
4799 SetVolumeSync(Sync, volptr);
4801 /* Does the caller has delete (&write) access to the parent dir? */
4802 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
4806 debugvnode2 = *parentptr;
4807 /* Do the actual delete of the desired (empty) directory, Name */
4808 if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
4809 Name, MustBeDIR))) {
4813 /* Update the status for the parent dir; link count is also adjusted */
4814 #if FS_STATS_DETAILED
4815 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4816 parentptr->disk.linkCount-1, client->InSameNetwork);
4818 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4819 parentptr->disk.linkCount-1);
4820 #endif /* FS_STATS_DETAILED */
4822 /* Return to the caller the updated parent dir status */
4823 GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4826 * Note: it is not necessary to break the callback on fileFid, since
4827 * refcount is now 0, so no one should be able to refer to the dir
4830 DeleteFileCallBacks(&fileFid);
4832 /* convert the write lock to a read lock before breaking callbacks */
4833 VVnodeWriteToRead(&errorCode, parentptr);
4834 assert(!errorCode || errorCode == VSALVAGE);
4836 /* break call back on DirFid and fileFid */
4837 BreakCallBack(client->host, DirFid, 0);
4840 /* Write the all modified vnodes (parent, new files) and volume back */
4841 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4843 ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
4846 } /*SAFSS_RemoveDir*/
4849 afs_int32 SRXAFS_RemoveDir (struct rx_call *acall,
4850 struct AFSFid *DirFid,
4852 struct AFSFetchStatus *OutDirStatus,
4853 struct AFSVolSync *Sync)
4856 struct rx_connection *tcon;
4857 #if FS_STATS_DETAILED
4858 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4859 struct timeval opStartTime,
4860 opStopTime; /* Start/stop times for RPC op*/
4861 struct timeval elapsedTime; /* Transfer time */
4864 * Set our stats pointer, remember when the RPC operation started, and
4865 * tally the operation.
4867 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
4871 TM_GetTimeOfDay(&opStartTime, 0);
4872 #endif /* FS_STATS_DETAILED */
4874 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4877 code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
4880 CallPostamble(tcon);
4882 #if FS_STATS_DETAILED
4883 TM_GetTimeOfDay(&opStopTime, 0);
4886 (opP->numSuccesses)++;
4887 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4888 fs_stats_AddTo((opP->sumTime), elapsedTime);
4889 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4890 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4891 fs_stats_TimeAssign((opP->minTime), elapsedTime);
4893 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4894 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4899 #endif /* FS_STATS_DETAILED */
4901 osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4904 } /*SRXAFS_RemoveDir*/
4908 * This routine is called exclusively by SRXAFS_SetLock(), and should be
4909 * merged into it when possible.
4912 SAFSS_SetLock (struct rx_call *acall,
4915 struct AFSVolSync *Sync)
4917 Vnode * targetptr = 0; /* vnode of input file */
4918 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4919 int errorCode = 0; /* error code */
4920 Volume * volptr = 0; /* pointer to the volume header */
4921 struct client * client; /* pointer to client structure */
4922 afs_int32 rights, anyrights; /* rights for this and any user */
4923 struct client *t_client; /* tmp ptr to client data */
4924 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
4925 static char * locktype[2] = {"LockRead","LockWrite"};
4926 struct rx_connection *tcon = rx_ConnectionOf(acall);
4928 if (type != LockRead && type != LockWrite) {
4932 /* Get ptr to client data for user Id for logging */
4933 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
4934 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
4935 ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
4936 locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
4937 inet_ntoa(logHostAddr), t_client->ViceId));
4939 AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
4943 * Get the vnode and volume for the desired file along with the caller's
4946 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
4947 DONTCHECK, &parentwhentargetnotdir,
4948 &client, WRITE_LOCK, &rights, &anyrights))) {
4952 /* set volume synchronization information */
4953 SetVolumeSync(Sync, volptr);
4955 /* Handle the particular type of set locking, type */
4956 errorCode = HandleLocking(targetptr, rights, type);
4959 /* Write the all modified vnodes (parent, new files) and volume back */
4960 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
4962 if ((errorCode == VREADONLY) && (type == LockRead))
4963 errorCode = 0; /* allow read locks on RO volumes without saving state */
4965 ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
4971 afs_int32 SRXAFS_OldSetLock(struct rx_call *acall,
4974 struct AFSVolSync *Sync)
4976 return SRXAFS_SetLock(acall, Fid, type, Sync);
4978 } /*SRXAFS_OldSetLock*/
4981 afs_int32 SRXAFS_SetLock (struct rx_call *acall,
4984 struct AFSVolSync *Sync)
4987 struct rx_connection *tcon;
4988 #if FS_STATS_DETAILED
4989 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4990 struct timeval opStartTime,
4991 opStopTime; /* Start/stop times for RPC op*/
4992 struct timeval elapsedTime; /* Transfer time */
4995 * Set our stats pointer, remember when the RPC operation started, and
4996 * tally the operation.
4998 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
5002 TM_GetTimeOfDay(&opStartTime, 0);
5003 #endif /* FS_STATS_DETAILED */
5005 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5008 code = SAFSS_SetLock (acall, Fid, type, Sync);
5011 CallPostamble(tcon);
5013 #if FS_STATS_DETAILED
5014 TM_GetTimeOfDay(&opStopTime, 0);
5017 (opP->numSuccesses)++;
5018 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5019 fs_stats_AddTo((opP->sumTime), elapsedTime);
5020 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5021 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5022 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5024 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5025 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5029 #endif /* FS_STATS_DETAILED */
5031 osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
5034 } /*SRXAFS_SetLock*/
5038 * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
5039 * merged into it when possible.
5042 SAFSS_ExtendLock (struct rx_call *acall,
5044 struct AFSVolSync *Sync)
5047 Vnode * targetptr = 0; /* vnode of input file */
5048 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5049 int errorCode = 0; /* error code */
5050 Volume * volptr = 0; /* pointer to the volume header */
5051 struct client * client; /* pointer to client structure */
5052 afs_int32 rights, anyrights; /* rights for this and any user */
5053 struct client *t_client; /* tmp ptr to client data */
5054 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
5055 struct rx_connection *tcon = rx_ConnectionOf(acall);
5057 /* Get ptr to client data for user Id for logging */
5058 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
5059 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
5060 ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n",
5061 Fid->Volume, Fid->Vnode, Fid->Unique,
5062 inet_ntoa(logHostAddr), t_client->ViceId));
5064 AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;
5067 * Get the vnode and volume for the desired file along with the caller's
5070 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5071 DONTCHECK, &parentwhentargetnotdir,
5072 &client, WRITE_LOCK, &rights, &anyrights))) {
5073 goto Bad_ExtendLock;
5076 /* set volume synchronization information */
5077 SetVolumeSync(Sync, volptr);
5079 /* Handle the actual lock extension */
5080 errorCode = HandleLocking(targetptr, rights, LockExtend);
5083 /* Put back file's vnode and volume */
5084 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5086 if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */
5087 errorCode = 0; /* under our generous policy re RO vols */
5089 ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
5092 } /*SAFSS_ExtendLock*/
5095 afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall,
5097 struct AFSVolSync *Sync)
5099 return SRXAFS_ExtendLock(acall, Fid, Sync);
5101 } /*SRXAFS_OldExtendLock*/
5104 afs_int32 SRXAFS_ExtendLock (struct rx_call *acall,
5106 struct AFSVolSync *Sync)
5109 struct rx_connection *tcon;
5110 #if FS_STATS_DETAILED
5111 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5112 struct timeval opStartTime,
5113 opStopTime; /* Start/stop times for RPC op*/
5114 struct timeval elapsedTime; /* Transfer time */
5117 * Set our stats pointer, remember when the RPC operation started, and
5118 * tally the operation.
5120 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
5124 TM_GetTimeOfDay(&opStartTime, 0);
5125 #endif /* FS_STATS_DETAILED */
5127 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5128 goto Bad_ExtendLock;
5130 code = SAFSS_ExtendLock (acall, Fid, Sync);
5133 CallPostamble(tcon);
5135 #if FS_STATS_DETAILED
5136 TM_GetTimeOfDay(&opStopTime, 0);
5139 (opP->numSuccesses)++;
5140 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5141 fs_stats_AddTo((opP->sumTime), elapsedTime);
5142 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5143 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5144 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5146 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5147 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5152 #endif /* FS_STATS_DETAILED */
5154 osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
5157 } /*SRXAFS_ExtendLock*/
5161 * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
5162 * merged into it when possible.
5165 SAFSS_ReleaseLock (struct rx_call *acall,
5167 struct AFSVolSync *Sync)
5170 Vnode * targetptr = 0; /* vnode of input file */
5171 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5172 int errorCode = 0; /* error code */
5173 Volume * volptr = 0; /* pointer to the volume header */
5174 struct client * client; /* pointer to client structure */
5175 afs_int32 rights, anyrights; /* rights for this and any user */
5176 struct client *t_client; /* tmp ptr to client data */
5177 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
5178 struct rx_connection *tcon = rx_ConnectionOf(acall);
5180 /* Get ptr to client data for user Id for logging */
5181 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
5182 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
5183 ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
5184 Fid->Volume, Fid->Vnode, Fid->Unique,
5185 inet_ntoa(logHostAddr), t_client->ViceId));
5187 AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
5190 * Get the vnode and volume for the desired file along with the caller's
5193 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5194 DONTCHECK, &parentwhentargetnotdir,
5195 &client, WRITE_LOCK, &rights, &anyrights))) {
5196 goto Bad_ReleaseLock;
5199 /* set volume synchronization information */
5200 SetVolumeSync(Sync, volptr);
5202 /* Handle the actual lock release */
5203 if ((errorCode = HandleLocking(targetptr, rights, LockRelease)))
5204 goto Bad_ReleaseLock;
5206 /* if no more locks left, a callback would be triggered here */
5207 if (targetptr->disk.lock.lockCount <= 0) {
5208 /* convert the write lock to a read lock before breaking callbacks */
5209 VVnodeWriteToRead(&errorCode, targetptr);
5210 assert(!errorCode || errorCode == VSALVAGE);
5211 BreakCallBack(client->host, Fid, 0);
5215 /* Put back file's vnode and volume */
5216 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5218 if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */
5219 errorCode = 0; /* under our generous policy re RO vols */
5221 ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
5224 } /*SAFSS_ReleaseLock*/
5227 afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall,
5229 struct AFSVolSync *Sync)
5231 return SRXAFS_ReleaseLock(acall, Fid, Sync);
5233 } /*SRXAFS_OldReleaseLock*/
5236 afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall,
5238 struct AFSVolSync *Sync)
5241 struct rx_connection *tcon;
5242 #if FS_STATS_DETAILED
5243 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5244 struct timeval opStartTime,
5245 opStopTime; /* Start/stop times for RPC op*/
5246 struct timeval elapsedTime; /* Transfer time */
5249 * Set our stats pointer, remember when the RPC operation started, and
5250 * tally the operation.
5252 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
5256 TM_GetTimeOfDay(&opStartTime, 0);
5257 #endif /* FS_STATS_DETAILED */
5259 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5260 goto Bad_ReleaseLock;
5262 code = SAFSS_ReleaseLock (acall, Fid, Sync);
5265 CallPostamble(tcon);
5267 #if FS_STATS_DETAILED
5268 TM_GetTimeOfDay(&opStopTime, 0);
5271 (opP->numSuccesses)++;
5272 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5273 fs_stats_AddTo((opP->sumTime), elapsedTime);
5274 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5275 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5276 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5278 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5279 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5284 #endif /* FS_STATS_DETAILED */
5286 osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
5289 } /*SRXAFS_ReleaseLock*/
5292 void SetSystemStats(struct AFSStatistics *stats)
5294 /* Fix this sometime soon.. */
5295 /* Because hey, it's not like we have a network monitoring protocol... */
5296 struct timeval time;
5298 /* this works on all system types */
5299 TM_GetTimeOfDay(&time, 0);
5300 stats->CurrentTime = time.tv_sec;
5301 } /*SetSystemStats*/
5303 void SetAFSStats(struct AFSStatistics *stats)
5305 extern afs_int32 StartTime, CurrentConnections;
5309 stats->CurrentMsgNumber = 0;
5310 stats->OldestMsgNumber = 0;
5311 stats->StartTime = StartTime;
5312 stats->CurrentConnections = CurrentConnections;
5313 stats->TotalAFSCalls = AFSCallStats.TotalCalls;
5314 stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
5315 stats->FetchDatas = AFSCallStats.FetchData;
5316 stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
5317 seconds = AFSCallStats.AccumFetchTime/1000;
5318 if (seconds <= 0) seconds = 1;
5319 stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
5320 stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
5321 stats->StoreDatas = AFSCallStats.StoreData;
5322 stats->StoredBytes = AFSCallStats.TotalStoredBytes;
5323 seconds = AFSCallStats.AccumStoreTime/1000;
5324 if (seconds <= 0) seconds = 1;
5325 stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
5327 stats->ProcessSize = -1; /* TODO: */
5329 stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
5332 h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
5333 (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
5337 /* Get disk related information from all AFS partitions. */
5339 void SetVolumeStats(struct AFSStatistics *stats)
5341 struct DiskPartition * part;
5344 for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
5345 stats->Disks[i].TotalBlocks = part->totalUsable;
5346 stats->Disks[i].BlocksAvailable = part->free;
5347 memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
5348 strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
5351 while (i < AFS_MSTATDISKS) {
5352 stats->Disks[i].TotalBlocks = -1;
5355 } /*SetVolumeStats*/
5357 afs_int32 SRXAFS_GetStatistics (struct rx_call *acall,
5358 struct ViceStatistics *Statistics)
5361 struct rx_connection *tcon;
5362 #if FS_STATS_DETAILED
5363 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5364 struct timeval opStartTime,
5365 opStopTime; /* Start/stop times for RPC op*/
5366 struct timeval elapsedTime; /* Transfer time */
5369 * Set our stats pointer, remember when the RPC operation started, and
5370 * tally the operation.
5372 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
5376 TM_GetTimeOfDay(&opStartTime, 0);
5377 #endif /* FS_STATS_DETAILED */
5379 if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
5380 goto Bad_GetStatistics;
5382 ViceLog(1, ("SAFS_GetStatistics Received\n"));
5384 AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
5386 memset(Statistics, 0, sizeof(*Statistics));
5387 SetAFSStats((struct AFSStatistics *)Statistics);
5388 SetVolumeStats((struct AFSStatistics *)Statistics);
5389 SetSystemStats((struct AFSStatistics *)Statistics);
5392 CallPostamble(tcon);
5394 #if FS_STATS_DETAILED
5395 TM_GetTimeOfDay(&opStopTime, 0);
5398 (opP->numSuccesses)++;
5399 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5400 fs_stats_AddTo((opP->sumTime), elapsedTime);
5401 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5402 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5403 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5405 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5406 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5410 #endif /* FS_STATS_DETAILED */
5414 } /*SRXAFS_GetStatistics*/
5417 /*------------------------------------------------------------------------
5418 * EXPORTED SRXAFS_XStatsVersion
5421 * Routine called by the server-side RPC interface to implement
5422 * pulling out the xstat version number for the File Server.
5425 * a_versionP : Ptr to the version number variable to set.
5431 * Nothing interesting.
5435 *------------------------------------------------------------------------*/
5437 afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
5438 { /*SRXAFS_XStatsVersion*/
5440 #if FS_STATS_DETAILED
5441 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5442 struct timeval opStartTime,
5443 opStopTime; /* Start/stop times for RPC op*/
5444 struct timeval elapsedTime; /* Transfer time */
5447 * Set our stats pointer, remember when the RPC operation started, and
5448 * tally the operation.
5450 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
5454 TM_GetTimeOfDay(&opStartTime, 0);
5455 #endif /* FS_STATS_DETAILED */
5457 *a_versionP = AFS_XSTAT_VERSION;
5459 #if FS_STATS_DETAILED
5460 TM_GetTimeOfDay(&opStopTime, 0);
5461 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5462 fs_stats_AddTo((opP->sumTime), elapsedTime);
5463 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5464 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5465 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5467 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5468 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5471 (opP->numSuccesses)++;
5473 #endif /* FS_STATS_DETAILED */
5477 } /*SRXAFS_XStatsVersion*/
5480 /*------------------------------------------------------------------------
5481 * PRIVATE FillPerfValues
5484 * Routine called to fill a regular performance data structure.
5487 * a_perfP : Ptr to perf structure to fill
5493 * Various collections need this info, so the guts were put in
5494 * this separate routine.
5498 *------------------------------------------------------------------------*/
5500 static void FillPerfValues(struct afs_PerfStats *a_perfP)
5501 { /*FillPerfValues*/
5503 int dir_Buffers; /*# buffers in use by dir package*/
5504 int dir_Calls; /*# read calls in dir package*/
5505 int dir_IOs; /*# I/O ops in dir package*/
5508 * Vnode cache section.
5510 a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
5511 a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
5512 a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
5513 a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
5514 a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
5515 a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
5516 a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
5517 a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
5518 a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
5519 a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
5520 a_perfP->vcache_H_Entries = VolumeCacheSize;
5521 a_perfP->vcache_H_Gets = VolumeGets;
5522 a_perfP->vcache_H_Replacements = VolumeReplacements;
5525 * Directory section.
5527 DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
5528 a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
5529 a_perfP->dir_Calls = (afs_int32 )dir_Calls;
5530 a_perfP->dir_IOs = (afs_int32) dir_IOs;
5535 a_perfP->rx_packetRequests =
5536 (afs_int32) rx_stats.packetRequests;
5537 a_perfP->rx_noPackets_RcvClass =
5538 (afs_int32) rx_stats.receivePktAllocFailures;
5539 a_perfP->rx_noPackets_SendClass =
5540 (afs_int32) rx_stats.sendPktAllocFailures;
5541 a_perfP->rx_noPackets_SpecialClass =
5542 (afs_int32) rx_stats.specialPktAllocFailures;
5543 a_perfP->rx_socketGreedy =
5544 (afs_int32) rx_stats.socketGreedy;
5545 a_perfP->rx_bogusPacketOnRead =
5546 (afs_int32) rx_stats.bogusPacketOnRead;
5547 a_perfP->rx_bogusHost =
5548 (afs_int32) rx_stats.bogusHost;
5549 a_perfP->rx_noPacketOnRead =
5550 (afs_int32) rx_stats.noPacketOnRead;
5551 a_perfP->rx_noPacketBuffersOnRead =
5552 (afs_int32) rx_stats.noPacketBuffersOnRead;
5553 a_perfP->rx_selects =
5554 (afs_int32) rx_stats.selects;
5555 a_perfP->rx_sendSelects =
5556 (afs_int32) rx_stats.sendSelects;
5557 a_perfP->rx_packetsRead_RcvClass =
5558 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
5559 a_perfP->rx_packetsRead_SendClass =
5560 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
5561 a_perfP->rx_packetsRead_SpecialClass =
5562 (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
5563 a_perfP->rx_dataPacketsRead =
5564 (afs_int32) rx_stats.dataPacketsRead;
5565 a_perfP->rx_ackPacketsRead =
5566 (afs_int32) rx_stats.ackPacketsRead;
5567 a_perfP->rx_dupPacketsRead =
5568 (afs_int32) rx_stats.dupPacketsRead;
5569 a_perfP->rx_spuriousPacketsRead =
5570 (afs_int32) rx_stats.spuriousPacketsRead;
5571 a_perfP->rx_packetsSent_RcvClass =
5572 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
5573 a_perfP->rx_packetsSent_SendClass =
5574 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
5575 a_perfP->rx_packetsSent_SpecialClass =
5576 (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
5577 a_perfP->rx_ackPacketsSent =
5578 (afs_int32) rx_stats.ackPacketsSent;
5579 a_perfP->rx_pingPacketsSent =
5580 (afs_int32) rx_stats.pingPacketsSent;
5581 a_perfP->rx_abortPacketsSent =
5582 (afs_int32) rx_stats.abortPacketsSent;
5583 a_perfP->rx_busyPacketsSent =
5584 (afs_int32) rx_stats.busyPacketsSent;
5585 a_perfP->rx_dataPacketsSent =
5586 (afs_int32) rx_stats.dataPacketsSent;
5587 a_perfP->rx_dataPacketsReSent =
5588 (afs_int32) rx_stats.dataPacketsReSent;
5589 a_perfP->rx_dataPacketsPushed =
5590 (afs_int32) rx_stats.dataPacketsPushed;
5591 a_perfP->rx_ignoreAckedPacket =
5592 (afs_int32) rx_stats.ignoreAckedPacket;
5593 a_perfP->rx_totalRtt_Sec =
5594 (afs_int32) rx_stats.totalRtt.sec;
5595 a_perfP->rx_totalRtt_Usec =
5596 (afs_int32) rx_stats.totalRtt.usec;
5597 a_perfP->rx_minRtt_Sec =
5598 (afs_int32) rx_stats.minRtt.sec;
5599 a_perfP->rx_minRtt_Usec =
5600 (afs_int32) rx_stats.minRtt.usec;
5601 a_perfP->rx_maxRtt_Sec =
5602 (afs_int32) rx_stats.maxRtt.sec;
5603 a_perfP->rx_maxRtt_Usec =
5604 (afs_int32) rx_stats.maxRtt.usec;
5605 a_perfP->rx_nRttSamples =
5606 (afs_int32) rx_stats.nRttSamples;
5607 a_perfP->rx_nServerConns =
5608 (afs_int32) rx_stats.nServerConns;
5609 a_perfP->rx_nClientConns =
5610 (afs_int32) rx_stats.nClientConns;
5611 a_perfP->rx_nPeerStructs =
5612 (afs_int32) rx_stats.nPeerStructs;
5613 a_perfP->rx_nCallStructs =
5614 (afs_int32) rx_stats.nCallStructs;
5615 a_perfP->rx_nFreeCallStructs =
5616 (afs_int32) rx_stats.nFreeCallStructs;
5618 a_perfP->host_NumHostEntries = HTs;
5619 a_perfP->host_HostBlocks = HTBlocks;
5620 h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
5621 &(a_perfP->host_HostsInSameNetOrSubnet),
5622 &(a_perfP->host_HostsInDiffSubnet),
5623 &(a_perfP->host_HostsInDiffNetwork));
5624 a_perfP->host_NumClients = CEs;
5625 a_perfP->host_ClientBlocks = CEBlocks;
5627 a_perfP->sysname_ID = afs_perfstats.sysname_ID;
5629 } /*FillPerfValues*/
5632 /*------------------------------------------------------------------------
5633 * EXPORTED SRXAFS_GetXStats
5636 * Routine called by the server-side callback RPC interface to
5637 * implement getting the given data collection from the extended
5638 * File Server statistics.
5641 * a_call : Ptr to Rx call on which this request came in.
5642 * a_clientVersionNum : Client version number.
5643 * a_opCode : Desired operation.
5644 * a_serverVersionNumP : Ptr to version number to set.
5645 * a_timeP : Ptr to time value (seconds) to set.
5646 * a_dataP : Ptr to variable array structure to return
5653 * Nothing interesting.
5657 *------------------------------------------------------------------------*/
5659 afs_int32 SRXAFS_GetXStats(struct rx_call *a_call,
5660 afs_int32 a_clientVersionNum,
5661 afs_int32 a_collectionNumber,
5662 afs_int32 *a_srvVersionNumP,
5664 AFS_CollData *a_dataP)
5665 { /*SRXAFS_GetXStats*/
5667 register int code; /*Return value*/
5668 afs_int32 *dataBuffP; /*Ptr to data to be returned*/
5669 afs_int32 dataBytes; /*Bytes in data buffer*/
5670 #if FS_STATS_DETAILED
5671 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5672 struct timeval opStartTime,
5673 opStopTime; /* Start/stop times for RPC op*/
5674 struct timeval elapsedTime; /* Transfer time */
5677 * Set our stats pointer, remember when the RPC operation started, and
5678 * tally the operation.
5680 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
5684 TM_GetTimeOfDay(&opStartTime, 0);
5685 #endif /* FS_STATS_DETAILED */
5688 * Record the time of day and the server version number.
5690 *a_srvVersionNumP = AFS_XSTAT_VERSION;
5691 *a_timeP = FT_ApproxTime();
5694 * Stuff the appropriate data in there (assume victory)
5698 ViceLog(1, ("Received GetXStats call for collection %d\n", a_collectionNumber));
5702 * We're not keeping stats, so just return successfully with
5705 a_dataP->AFS_CollData_len = 0;
5706 a_dataP->AFS_CollData_val = NULL;
5709 switch(a_collectionNumber) {
5710 case AFS_XSTATSCOLL_CALL_INFO:
5712 * Pass back all the call-count-related data.
5714 * >>> We are forced to allocate a separate area in which to
5715 * >>> put this stuff in by the RPC stub generator, since it
5716 * >>> will be freed at the tail end of the server stub code.
5720 * I don't think call-level stats are being collected yet
5721 * for the File Server.
5723 dataBytes = sizeof(struct afs_Stats);
5724 dataBuffP = (afs_int32 *)malloc(dataBytes);
5725 memcpy(dataBuffP, &afs_cmstats, dataBytes);
5726 a_dataP->AFS_CollData_len = dataBytes>>2;
5727 a_dataP->AFS_CollData_val = dataBuffP;
5729 a_dataP->AFS_CollData_len = 0;
5730 a_dataP->AFS_CollData_val = NULL;
5734 case AFS_XSTATSCOLL_PERF_INFO:
5736 * Pass back all the regular performance-related data.
5738 * >>> We are forced to allocate a separate area in which to
5739 * >>> put this stuff in by the RPC stub generator, since it
5740 * >>> will be freed at the tail end of the server stub code.
5743 afs_perfstats.numPerfCalls++;
5744 FillPerfValues(&afs_perfstats);
5747 * Don't overwrite the spares at the end.
5750 dataBytes = sizeof(struct afs_PerfStats);
5751 dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5752 memcpy(dataBuffP, &afs_perfstats, dataBytes);
5753 a_dataP->AFS_CollData_len = dataBytes>>2;
5754 a_dataP->AFS_CollData_val = dataBuffP;
5757 case AFS_XSTATSCOLL_FULL_PERF_INFO:
5759 * Pass back the full collection of performance-related data.
5760 * We have to stuff the basic, overall numbers in, but the
5761 * detailed numbers are kept in the structure already.
5763 * >>> We are forced to allocate a separate area in which to
5764 * >>> put this stuff in by the RPC stub generator, since it
5765 * >>> will be freed at the tail end of the server stub code.
5768 afs_perfstats.numPerfCalls++;
5769 #if FS_STATS_DETAILED
5770 afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
5771 FillPerfValues(&afs_FullPerfStats.overall);
5774 * Don't overwrite the spares at the end.
5777 dataBytes = sizeof(struct fs_stats_FullPerfStats);
5778 dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5779 memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
5780 a_dataP->AFS_CollData_len = dataBytes>>2;
5781 a_dataP->AFS_CollData_val = dataBuffP;
5787 * Illegal collection number.
5789 a_dataP->AFS_CollData_len = 0;
5790 a_dataP->AFS_CollData_val = NULL;
5792 } /*Switch on collection number*/
5794 #if FS_STATS_DETAILED
5795 TM_GetTimeOfDay(&opStopTime, 0);
5798 (opP->numSuccesses)++;
5799 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5800 fs_stats_AddTo((opP->sumTime), elapsedTime);
5801 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5802 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5803 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5805 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5806 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5811 #endif /* FS_STATS_DETAILED */
5815 } /*SRXAFS_GetXStats*/
5818 afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall,
5819 struct AFSCBFids *FidArray,
5820 struct AFSCBs *CallBackArray)
5822 afs_int32 errorCode;
5824 struct client *client;
5825 struct rx_connection *tcon;
5826 #if FS_STATS_DETAILED
5827 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
5828 struct timeval opStartTime,
5829 opStopTime; /* Start/stop times for RPC op*/
5830 struct timeval elapsedTime; /* Transfer time */
5833 * Set our stats pointer, remember when the RPC operation started, and
5834 * tally the operation.
5836 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
5840 TM_GetTimeOfDay(&opStartTime, 0);
5841 #endif /* FS_STATS_DETAILED */
5843 ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
5845 AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
5847 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
5848 goto Bad_GiveUpCallBacks;
5850 if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
5851 ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n",
5852 FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len,
5853 (tcon->peer ? tcon->peer->host : 0)));
5855 goto Bad_GiveUpCallBacks;
5858 errorCode = GetClient(tcon, &client);
5860 for (i=0; i < FidArray->AFSCBFids_len; i++) {
5861 register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
5862 DeleteCallBack(client->host, fid);
5866 Bad_GiveUpCallBacks:
5867 CallPostamble(tcon);
5869 #if FS_STATS_DETAILED
5870 TM_GetTimeOfDay(&opStopTime, 0);
5871 if (errorCode == 0) {
5873 (opP->numSuccesses)++;
5874 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5875 fs_stats_AddTo((opP->sumTime), elapsedTime);
5876 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5877 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5878 fs_stats_TimeAssign((opP->minTime), elapsedTime);
5880 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5881 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5885 #endif /* FS_STATS_DETAILED */
5889 } /*SRXAFS_GiveUpCallBacks*/
5892 afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall,
5894 struct AFSVolumeInfo *avolinfo)
5896 return(VNOVOL); /* XXX Obsolete routine XXX */
5898 } /*SRXAFS_NGetVolumeInfo*/
5902 * Dummy routine. Should never be called (the cache manager should only
5903 * invoke this interface when communicating with a AFS/DFS Protocol
5906 afs_int32 SRXAFS_Lookup(struct rx_call *call_p,
5907 struct AFSFid *afs_dfid_p,
5909 struct AFSFid *afs_fid_p,
5910 struct AFSFetchStatus *afs_status_p,
5911 struct AFSFetchStatus *afs_dir_status_p,
5912 struct AFSCallBack *afs_callback_p,
5913 struct AFSVolSync *afs_sync_p)
5919 afs_int32 SRXAFS_FlushCPS(struct rx_call *acall,
5920 struct ViceIds *vids,
5921 struct IPAddrs *addrs,
5927 afs_int32 nids, naddrs;
5928 afs_int32 *vd, *addr;
5929 int errorCode = 0; /* return code to caller */
5930 struct client *client;
5931 struct rx_connection *tcon = rx_ConnectionOf(acall);
5933 ViceLog(1, ("SRXAFS_FlushCPS\n"));
5935 AFSCallStats.TotalCalls++;
5937 nids = vids->ViceIds_len; /* # of users in here */
5938 naddrs = addrs->IPAddrs_len; /* # of hosts in here */
5939 if (nids < 0 || naddrs < 0) {
5944 vd = vids->ViceIds_val;
5945 for (i=0; i<nids; i++, vd++) {
5948 client = h_ID2Client(*vd); /* returns client locked, or NULL */
5952 BoostSharedLock(&client->lock);
5953 client->prfail = 2; /* Means re-eval client's cps */
5956 rx_SetRock(((struct rx_connection *) client->tcon), 0);
5959 if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
5960 free(client->CPS.prlist_val);
5961 client->CPS.prlist_val = NULL;
5963 ReleaseWriteLock(&client->lock);
5966 addr = addrs->IPAddrs_val;
5967 for (i=0; i<naddrs; i++, addr++) {
5969 h_flushhostcps(*addr, 7001);
5973 ViceLog(2, ("SAFS_FlushCPS returns %d\n", errorCode));
5975 } /*SRXAFS_FlushCPS */
5977 /* worthless hack to let CS keep running ancient software */
5978 static int afs_vtoi(register char *aname)
5980 register afs_int32 temp;
5984 while((tc = *aname++)) {
5985 if (tc > '9' || tc < '0') return 0; /* invalid name */
5993 * may get name or #, but must handle all weird cases (recognize readonly
5994 * or backup volumes by name or #
5996 static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave,
5997 register struct VolumeInfo *av)
5999 register int i, j, vol;
6000 afs_int32 mask, whichType;
6001 afs_uint32 *serverHost, *typePtr;
6003 /* figure out what type we want if by name */
6005 if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
6006 whichType = BACKVOL;
6007 else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
6009 else whichType = RWVOL;
6011 vol = afs_vtoi(aname);
6012 if (vol == 0) vol = ave->volumeId[whichType];
6015 * Now vol has volume # we're interested in. Next, figure out the type
6016 * of the volume by looking finding it in the vldb entry
6018 if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
6022 else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
6026 else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
6027 mask = VLSF_RWVOL; /* backup always is on the same volume as parent */
6028 whichType = BACKVOL;
6031 return EINVAL; /* error: can't find volume in vldb entry */
6033 typePtr = &av->Type0;
6034 serverHost = &av->Server0;
6036 av->Type = whichType;
6037 av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
6038 if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
6039 if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
6040 if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
6042 for(i=0,j=0; i<ave->nServers; i++) {
6043 if ((ave->serverFlags[i] & mask) == 0) continue; /* wrong volume */
6044 serverHost[j] = ave->serverNumber[i];
6047 av->ServerCount = j;
6048 if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
6052 static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo)
6054 static struct rx_connection *vlConn = 0;
6055 static int down = 0;
6056 static afs_int32 lastDownTime = 0;
6057 struct vldbentry tve;
6058 struct rx_securityClass *vlSec;
6059 register afs_int32 code;
6062 vlSec = rxnull_NewClientSecurityObject();
6063 vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
6064 rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
6066 if (down && (FT_ApproxTime() < lastDownTime + 180)) {
6067 return 1; /* failure */
6070 code = VL_GetEntryByNameO(vlConn, avolid, &tve);
6071 if (code >= 0) down = 0; /* call worked */
6074 lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
6080 /* otherwise convert to old format vldb entry */
6081 code = CopyVolumeEntry(avolid, &tve, avolinfo);
6090 afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall,
6092 struct VolumeInfo *avolinfo)
6095 struct rx_connection *tcon;
6096 #if FS_STATS_DETAILED
6097 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6098 struct timeval opStartTime,
6099 opStopTime; /* Start/stop times for RPC op*/
6100 struct timeval elapsedTime; /* Transfer time */
6103 * Set our stats pointer, remember when the RPC operation started, and
6104 * tally the operation.
6106 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
6110 TM_GetTimeOfDay(&opStartTime, 0);
6111 #endif /* FS_STATS_DETAILED */
6112 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6113 goto Bad_GetVolumeInfo;
6116 AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
6119 code = TryLocalVLServer(avolid, avolinfo);
6120 ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
6121 code, avolinfo->Vid, avolinfo->Type,
6122 avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
6123 avolinfo->Server3));
6124 avolinfo->Type4 = 0xabcd9999; /* tell us to try new vldb */
6127 CallPostamble(tcon);
6129 #if FS_STATS_DETAILED
6130 TM_GetTimeOfDay(&opStopTime, 0);
6133 (opP->numSuccesses)++;
6134 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6135 fs_stats_AddTo((opP->sumTime), elapsedTime);
6136 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6137 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6138 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6140 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6141 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6146 #endif /* FS_STATS_DETAILED */
6150 } /*SRXAFS_GetVolumeInfo*/
6153 afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall,
6155 AFSFetchVolumeStatus *FetchVolStatus,
6160 Vnode * targetptr = 0; /* vnode of the new file */
6161 Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6162 int errorCode = 0; /* error code */
6163 Volume * volptr = 0; /* pointer to the volume header */
6164 struct client * client; /* pointer to client entry */
6165 afs_int32 rights, anyrights; /* rights for this and any user */
6167 struct rx_connection *tcon;
6168 #if FS_STATS_DETAILED
6169 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6170 struct timeval opStartTime,
6171 opStopTime; /* Start/stop times for RPC op*/
6172 struct timeval elapsedTime; /* Transfer time */
6175 * Set our stats pointer, remember when the RPC operation started, and
6176 * tally the operation.
6178 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
6182 TM_GetTimeOfDay(&opStartTime, 0);
6183 #endif /* FS_STATS_DETAILED */
6185 ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
6186 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6187 goto Bad_GetVolumeStatus;
6190 AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
6195 goto Bad_GetVolumeStatus;
6197 dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6199 if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6200 MustBeDIR, &parentwhentargetnotdir,
6201 &client, READ_LOCK, &rights, &anyrights)))
6202 goto Bad_GetVolumeStatus;
6204 if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
6206 goto Bad_GetVolumeStatus;
6208 RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
6210 Bad_GetVolumeStatus:
6211 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6212 ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
6213 /* next is to guarantee out strings exist for stub */
6214 if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
6215 if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
6216 if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
6217 CallPostamble(tcon);
6219 #if FS_STATS_DETAILED
6220 TM_GetTimeOfDay(&opStopTime, 0);
6221 if (errorCode == 0) {
6223 (opP->numSuccesses)++;
6224 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6225 fs_stats_AddTo((opP->sumTime), elapsedTime);
6226 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6227 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6228 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6230 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6231 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6236 #endif /* FS_STATS_DETAILED */
6239 } /*SRXAFS_GetVolumeStatus*/
6242 afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall,
6244 AFSStoreVolumeStatus *StoreVolStatus,
6249 Vnode * targetptr = 0; /* vnode of the new file */
6250 Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6251 int errorCode = 0; /* error code */
6252 Volume * volptr = 0; /* pointer to the volume header */
6253 struct client * client; /* pointer to client entry */
6254 afs_int32 rights, anyrights; /* rights for this and any user */
6256 struct rx_connection *tcon = rx_ConnectionOf(acall);
6257 #if FS_STATS_DETAILED
6258 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6259 struct timeval opStartTime,
6260 opStopTime; /* Start/stop times for RPC op*/
6261 struct timeval elapsedTime; /* Transfer time */
6264 * Set our stats pointer, remember when the RPC operation started, and
6265 * tally the operation.
6267 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
6271 TM_GetTimeOfDay(&opStartTime, 0);
6272 #endif /* FS_STATS_DETAILED */
6274 ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
6275 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6276 goto Bad_SetVolumeStatus;
6279 AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
6284 goto Bad_SetVolumeStatus;
6286 dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6288 if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6289 MustBeDIR, &parentwhentargetnotdir,
6290 &client, READ_LOCK, &rights, &anyrights)))
6291 goto Bad_SetVolumeStatus;
6293 if (readonlyServer) {
6294 errorCode = VREADONLY;
6295 goto Bad_SetVolumeStatus;
6297 if (VanillaUser(client)) {
6299 goto Bad_SetVolumeStatus;
6302 errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
6305 Bad_SetVolumeStatus:
6306 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6307 ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
6308 CallPostamble(tcon);
6310 #if FS_STATS_DETAILED
6311 TM_GetTimeOfDay(&opStopTime, 0);
6312 if (errorCode == 0) {
6314 (opP->numSuccesses)++;
6315 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6316 fs_stats_AddTo((opP->sumTime), elapsedTime);
6317 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6318 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6319 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6321 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6322 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6327 #endif /* FS_STATS_DETAILED */
6329 osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
6332 } /*SRXAFS_SetVolumeStatus*/
6334 #define DEFAULTVOLUME "root.afs"
6336 afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName)
6341 int errorCode = 0; /* error code */
6342 struct rx_connection *tcon;
6343 #if FS_STATS_DETAILED
6344 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6345 struct timeval opStartTime,
6346 opStopTime; /* Start/stop times for RPC op*/
6347 struct timeval elapsedTime; /* Transfer time */
6350 * Set our stats pointer, remember when the RPC operation started, and
6351 * tally the operation.
6353 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
6357 TM_GetTimeOfDay(&opStartTime, 0);
6358 #endif /* FS_STATS_DETAILED */
6360 return FSERR_EOPNOTSUPP;
6363 if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
6364 goto Bad_GetRootVolume;
6366 AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
6370 fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
6372 strcpy(temp, DEFAULTVOLUME);
6374 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6375 lockf(fd, F_LOCK, 0);
6379 len = read(fd, temp, 256);
6380 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6381 lockf(fd, F_ULOCK, 0);
6386 if (temp[len-1] == '\n') len--;
6389 *VolumeName = temp; /* freed by rx server-side stub */
6392 CallPostamble(tcon);
6394 #if FS_STATS_DETAILED
6395 TM_GetTimeOfDay(&opStopTime, 0);
6396 if (errorCode == 0) {
6398 (opP->numSuccesses)++;
6399 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6400 fs_stats_AddTo((opP->sumTime), elapsedTime);
6401 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6402 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6403 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6405 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6406 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6410 #endif /* FS_STATS_DETAILED */
6415 } /*SRXAFS_GetRootVolume*/
6418 /* still works because a struct CBS is the same as a struct AFSOpaque */
6419 afs_int32 SRXAFS_CheckToken (struct rx_call *acall,
6421 struct AFSOpaque *Token)
6424 struct rx_connection *tcon;
6425 #if FS_STATS_DETAILED
6426 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6427 struct timeval opStartTime,
6428 opStopTime; /* Start/stop times for RPC op*/
6429 struct timeval elapsedTime; /* Transfer time */
6432 * Set our stats pointer, remember when the RPC operation started, and
6433 * tally the operation.
6435 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
6439 TM_GetTimeOfDay(&opStartTime, 0);
6440 #endif /* FS_STATS_DETAILED */
6442 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6443 goto Bad_CheckToken;
6445 code = FSERR_ECONNREFUSED;
6448 CallPostamble(tcon);
6450 #if FS_STATS_DETAILED
6451 TM_GetTimeOfDay(&opStopTime, 0);
6454 (opP->numSuccesses)++;
6455 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6456 fs_stats_AddTo((opP->sumTime), elapsedTime);
6457 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6458 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6459 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6461 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6462 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6467 #endif /* FS_STATS_DETAILED */
6471 } /*SRXAFS_CheckToken*/
6473 afs_int32 SRXAFS_GetTime (struct rx_call *acall,
6474 afs_uint32 *Seconds,
6475 afs_uint32 *USeconds)
6478 struct rx_connection *tcon;
6480 #if FS_STATS_DETAILED
6481 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
6482 struct timeval opStartTime,
6483 opStopTime; /* Start/stop times for RPC op*/
6484 struct timeval elapsedTime; /* Transfer time */
6487 * Set our stats pointer, remember when the RPC operation started, and
6488 * tally the operation.
6490 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
6494 TM_GetTimeOfDay(&opStartTime, 0);
6495 #endif /* FS_STATS_DETAILED */
6497 if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
6501 AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
6504 TM_GetTimeOfDay(&tpl, 0);
6505 *Seconds = tpl.tv_sec;
6506 *USeconds = tpl.tv_usec;
6508 ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
6511 CallPostamble(tcon);
6513 #if FS_STATS_DETAILED
6514 TM_GetTimeOfDay(&opStopTime, 0);
6515 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6518 (opP->numSuccesses)++;
6519 fs_stats_AddTo((opP->sumTime), elapsedTime);
6520 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6521 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6522 fs_stats_TimeAssign((opP->minTime), elapsedTime);
6524 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6525 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6530 #endif /* FS_STATS_DETAILED */
6534 } /*SRXAFS_GetTime*/
6541 * Implement a client's data fetch using Rx.
6544 * volptr : Ptr to the given volume's info.
6545 * targetptr : Pointer to the vnode involved.
6546 * Call : Ptr to the Rx call involved.
6547 * Pos : Offset within the file.
6548 * Len : Length in bytes to read; this value is bogus!
6549 * if FS_STATS_DETAILED
6550 * a_bytesToFetchP : Set to the number of bytes to be fetched from
6552 * a_bytesFetchedP : Set to the actual number of bytes fetched from
6558 FetchData_RXStyle(Volume *volptr,
6560 register struct rx_call *Call,
6563 afs_int32 Int64Mode,
6564 #if FS_STATS_DETAILED
6565 afs_size_t *a_bytesToFetchP,
6566 afs_size_t *a_bytesFetchedP
6567 #endif /* FS_STATS_DETAILED */
6570 struct timeval StartTime, StopTime; /* used to calculate file transfer rates */
6571 int errorCode = 0; /* Returned error code to caller */
6576 register char *tbuffer;
6577 #else /* AFS_NT40_ENV */
6578 struct iovec tiov[RX_MAXIOVECS];
6580 #endif /* AFS_NT40_ENV */
6585 struct statfs tstatfs;
6588 #if FS_STATS_DETAILED
6590 * Initialize the byte count arguments.
6592 (*a_bytesToFetchP) = 0;
6593 (*a_bytesFetchedP) = 0;
6594 #endif /* FS_STATS_DETAILED */
6596 #ifdef AFS_LARGEFILE_ENV
6597 ViceLog(25, ("FetchData_RXStyle: Pos (0X%x,0X%x), Len (0X%x,0X%x)\n",
6598 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6599 (unsigned) (Len >> 32), (unsigned) (Len & 0xffffffff)));
6600 #else /* !AFS_LARGEFILE_ENV */
6601 ViceLog(25, ("FetchData_RXStyle: Pos 0X%x, Len 0X%x\n",
6604 #endif /* !AFS_LARGEFILE_ENV */
6606 if (!VN_GET_INO(targetptr)) {
6607 afs_int32 zero = htonl(0);
6609 * This is used for newly created files; we simply send 0 bytes
6610 * back to make the cache manager happy...
6613 rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* send 0-length */
6614 rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* send 0-length */
6617 TM_GetTimeOfDay(&StartTime, 0);
6618 ihP = targetptr->handle;
6620 if (fdP == NULL) return EIO;
6621 optSize = sendBufSize;
6622 tlen = FDH_SIZE(fdP);
6623 #ifdef AFS_LARGEFILE_ENV
6624 ViceLog( 25, ("FetchData_RXStyle: file size (0X%x,0X%x)\n",
6625 (unsigned) (tlen >> 32), (unsigned) (tlen & 0xffffffff)));
6626 #else /* !AFS_LARGEFILE_ENV */
6627 ViceLog( 25, ("FetchData_RXStyle: file size 0X%x\n",
6629 #endif /* !AFS_LARGEFILE_ENV */
6635 if (Pos + Len > tlen) Len = tlen - Pos; /* get length we should send */
6636 FDH_SEEK(fdP, Pos, 0);
6638 afs_int32 high, low;
6639 SplitInt64(Len, high, low);
6640 assert(Int64Mode || high==0);
6643 rx_Write(Call, (char *)&high, sizeof(afs_int32)); /* High order bits */
6646 rx_Write(Call, (char *)&low, sizeof(afs_int32)); /* send length on fetch */
6648 #if FS_STATS_DETAILED
6649 (*a_bytesToFetchP) = Len;
6650 #endif /* FS_STATS_DETAILED */
6652 tbuffer = AllocSendBuffer();
6653 #endif /* AFS_NT40_ENV */
6655 if (Len > optSize) tlen = optSize;
6658 errorCode = FDH_READ(fdP, tbuffer, tlen);
6659 if (errorCode != tlen) {
6661 FreeSendBuffer((struct afs_buffer *) tbuffer);
6664 errorCode = rx_Write(Call, tbuffer, tlen);
6665 #else /* AFS_NT40_ENV */
6666 errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6667 if (errorCode <= 0) {
6672 errorCode = FDH_READV(fdP, tiov, tnio);
6673 if (errorCode != tlen) {
6677 errorCode = rx_Writev(Call, tiov, tnio, tlen);
6678 #endif /* AFS_NT40_ENV */
6679 #if FS_STATS_DETAILED
6681 * Bump the number of bytes actually sent by the number from this
6684 (*a_bytesFetchedP) += errorCode;
6685 #endif /* FS_STATS_DETAILED */
6686 if (errorCode != tlen) {
6689 FreeSendBuffer((struct afs_buffer *) tbuffer);
6690 #endif /* AFS_NT40_ENV */
6696 FreeSendBuffer((struct afs_buffer *) tbuffer);
6697 #endif /* AFS_NT40_ENV */
6699 TM_GetTimeOfDay(&StopTime, 0);
6701 /* Adjust all Fetch Data related stats */
6703 if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
6704 AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
6705 AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
6706 ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
6709 VN_GET_LEN(targLen, targetptr);
6710 AFSCallStats.TotalFetchedBytes += targLen;
6711 AFSCallStats.FetchSize1++;
6712 if (targLen < SIZE2)
6713 AFSCallStats.FetchSize2++;
6714 else if (targLen < SIZE3)
6715 AFSCallStats.FetchSize3++;
6716 else if (targLen < SIZE4)
6717 AFSCallStats.FetchSize4++;
6719 AFSCallStats.FetchSize5++;
6724 } /*FetchData_RXStyle*/
6726 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, afs_size_t *size)
6728 #ifdef AFS_NAMEI_ENV
6730 lhp = IH_OPEN(V_linkHandle(vp));
6734 *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6736 *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6741 *size = OS_SIZE(fdP->fd_fd);
6742 return (*size == -1) ? -1 : 0;
6746 if (fstat(fdP->fd_fd, &status)<0) {
6750 *lc = GetLinkCount(vp, &status);
6751 *size = status.st_size;
6760 * Implement a client's data store using Rx.
6763 * volptr : Ptr to the given volume's info.
6764 * targetptr : Pointer to the vnode involved.
6765 * Call : Ptr to the Rx call involved.
6766 * Pos : Offset within the file.
6767 * Len : Length in bytes to store; this value is bogus!
6768 * if FS_STATS_DETAILED
6769 * a_bytesToStoreP : Set to the number of bytes to be stored to
6771 * a_bytesStoredP : Set to the actual number of bytes stored to
6776 StoreData_RXStyle(Volume *volptr,
6779 struct client *client,
6780 register struct rx_call *Call,
6783 afs_offs_t FileLength,
6785 #if FS_STATS_DETAILED
6786 afs_size_t *a_bytesToStoreP,
6787 afs_size_t *a_bytesStoredP
6788 #endif /* FS_STATS_DETAILED */
6791 afs_size_t bytesTransfered; /* number of bytes actually transfered */
6792 struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
6793 int errorCode = 0; /* Returned error code to caller */
6795 register char *tbuffer; /* data copying buffer */
6796 #else /* AFS_NT40_ENV */
6797 struct iovec tiov[RX_MAXIOVECS]; /* no data copying with iovec */
6798 int tnio; /* temp for iovec size */
6799 #endif /* AFS_NT40_ENV */
6800 afs_size_t tlen; /* temp for xfr length */
6801 Inode tinode; /* inode for I/O */
6802 afs_size_t optSize; /* optimal transfer size */
6803 afs_size_t DataLength; /* size of inode */
6804 afs_size_t TruncatedLength; /* size after ftruncate */
6805 afs_offs_t NewLength; /* size after this store completes */
6806 afs_size_t adjustSize; /* bytes to call VAdjust... with */
6807 int linkCount; /* link count on inode */
6810 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
6812 #if FS_STATS_DETAILED
6814 * Initialize the byte count arguments.
6816 (*a_bytesToStoreP) = 0;
6817 (*a_bytesStoredP) = 0;
6818 #endif /* FS_STATS_DETAILED */
6821 * We break the callbacks here so that the following signal will not
6824 BreakCallBack(client->host, Fid, 0);
6826 if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
6827 /* the inode should have been created in Alloc_NewVnode */
6828 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
6829 ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
6830 Fid->Volume, Fid->Vnode, Fid->Unique,
6831 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
6832 return ENOENT; /* is this proper error code? */
6836 * See if the file has several links (from other volumes). If it
6837 * does, then we have to make a copy before changing it to avoid
6838 *changing read-only clones of this dude
6840 ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
6841 PrintInode(NULL, VN_GET_INO(targetptr))));
6842 fdP = IH_OPEN(targetptr->handle);
6845 if (GetLinkCountAndSize(volptr, fdP, &linkCount,
6851 if (linkCount != 1) {
6853 ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
6854 PrintInode(NULL, VN_GET_INO(targetptr))));
6855 /* other volumes share this data, better copy it first */
6857 /* Adjust the disk block count by the creation of the new inode.
6858 * We call the special VDiskUsage so we don't adjust the volume's
6859 * quota since we don't want to penalyze the user for afs's internal
6860 * mechanisms (i.e. copy on write overhead.) Also the right size
6861 * of the disk will be recorded...
6864 VN_GET_LEN(size, targetptr);
6865 volptr->partition->flags &= ~PART_DONTUPDATE;
6866 VSetPartitionDiskUsage(volptr->partition);
6867 volptr->partition->flags |= PART_DONTUPDATE;
6868 if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
6869 volptr->partition->flags &= ~PART_DONTUPDATE;
6873 ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n"));
6874 if ((errorCode = CopyOnWrite(targetptr, volptr)))
6876 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6877 volptr->partition->flags &= ~PART_DONTUPDATE;
6880 volptr->partition->flags &= ~PART_DONTUPDATE;
6881 VSetPartitionDiskUsage(volptr->partition);
6882 fdP = IH_OPEN(targetptr->handle);
6884 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
6888 tinode = VN_GET_INO(targetptr);
6890 assert(VALID_INO(tinode));
6892 /* compute new file length */
6893 NewLength = DataLength;
6894 if (FileLength < NewLength)
6895 /* simulate truncate */
6896 NewLength = FileLength;
6897 TruncatedLength = NewLength; /* remember length after possible ftruncate */
6898 if (Pos + Length > NewLength)
6899 NewLength = Pos+Length; /* and write */
6901 /* adjust the disk block count by the difference in the files */
6903 afs_size_t targSize;
6904 VN_GET_LEN(targSize, targetptr);
6905 adjustSize = nBlocks(NewLength) - nBlocks(targSize);
6907 if((errorCode = AdjustDiskUsage(volptr, adjustSize,
6908 adjustSize - SpareComp(volptr)))) {
6913 /* can signal cache manager to proceed from close now */
6914 /* this bit means that the locks are set and protections are OK */
6915 rx_SetLocalStatus(Call, 1);
6917 TM_GetTimeOfDay(&StartTime, 0);
6919 optSize = sendBufSize;
6921 #ifdef AFS_LARGEFILE_ENV
6922 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",
6923 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6924 (unsigned) (DataLength >> 32), (unsigned) (DataLength & 0xffffffff),
6925 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff),
6926 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff)));
6927 #else /* !AFS_LARGEFILE_ENV */
6928 ViceLog(25, ("StoreData_RXStyle: Pos 0X%x, DataLength 0X%x, FileLength 0X%x, Length 0X%x\n",
6930 (unsigned) DataLength,
6931 (unsigned) FileLength,
6932 (unsigned) Length));
6933 #endif /* !AFS_LARGEFILE_ENV */
6935 /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
6936 if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
6937 if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
6938 bytesTransfered = 0;
6940 tbuffer = AllocSendBuffer();
6941 #endif /* AFS_NT40_ENV */
6942 /* if length == 0, the loop below isn't going to do anything, including
6943 * extend the length of the inode, which it must do, since the file system
6944 * assumes that the inode length == vnode's file length. So, we extend
6945 * the file length manually if need be. Note that if file is bigger than
6946 * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
6947 * do what we're going to do below.
6949 if (Length == 0 && Pos > TruncatedLength) {
6950 /* Set the file's length; we've already done an lseek to the right
6953 errorCode = FDH_WRITE(fdP, &tlen, 1);
6954 if (errorCode != 1) goto done;
6955 errorCode = FDH_TRUNC(fdP, Pos);
6958 /* have some data to copy */
6959 #if FS_STATS_DETAILED
6960 (*a_bytesToStoreP) = Length;
6961 #endif /* FS_STATS_DETAILED */
6963 if (bytesTransfered >= Length) {
6967 tlen = Length - bytesTransfered; /* how much more to do */
6968 if (tlen > optSize) tlen = optSize; /* bound by buffer size */
6970 errorCode = rx_Read(Call, tbuffer, tlen);
6971 #else /* AFS_NT40_ENV */
6972 errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6973 #endif /* AFS_NT40_ENV */
6974 #if FS_STATS_DETAILED
6975 (*a_bytesStoredP) += errorCode;
6976 #endif /* FS_STATS_DETAILED */
6977 if (errorCode <= 0) {
6983 errorCode = FDH_WRITE(fdP, tbuffer, tlen);
6984 #else /* AFS_NT40_ENV */
6985 errorCode = FDH_WRITEV(fdP, tiov, tnio);
6986 #endif /* AFS_NT40_ENV */
6987 if (errorCode != tlen) {
6988 errorCode = VDISKFULL;
6991 bytesTransfered += tlen;
6996 FreeSendBuffer((struct afs_buffer *) tbuffer);
6997 #endif /* AFS_NT40_ENV */
7002 afs_size_t nfSize = FDH_SIZE(fdP);
7003 /* something went wrong: adjust size and return */
7004 VN_SET_LEN(targetptr, nfSize); /* set new file size. */
7005 /* changed_newTime is tested in StoreData to detemine if we
7006 * need to update the target vnode.
7008 targetptr->changed_newTime = 1;
7010 /* set disk usage to be correct */
7011 VAdjustDiskUsage(&errorCode, volptr,
7012 (afs_size_t)(nBlocks(nfSize) - nBlocks(NewLength)),
7018 TM_GetTimeOfDay(&StopTime, 0);
7020 VN_SET_LEN(targetptr, NewLength);
7022 /* Update all StoreData related stats */
7024 if (AFSCallStats.TotalStoredBytes > 2000000000) /* reset if over 2 billion */
7025 AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
7026 AFSCallStats.StoreSize1++; /* Piggybacked data */
7029 VN_GET_LEN(targLen, targetptr);
7030 if (targLen < SIZE2)
7031 AFSCallStats.StoreSize2++;
7032 else if (targLen < SIZE3)
7033 AFSCallStats.StoreSize3++;
7034 else if (targLen < SIZE4)
7035 AFSCallStats.StoreSize4++;
7037 AFSCallStats.StoreSize5++;
7042 } /*StoreData_RXStyle*/