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*/