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>
111 #include <afs/audit.h>
112 #include <afs/afsutil.h>
114 #ifdef AFS_PTHREAD_ENV
115 pthread_mutex_t fileproc_glock_mutex;
116 #endif /* AFS_PTHREAD_ENV */
119 /* Useful local defines used by this module */
122 #define MustNOTBeDIR 1
126 #define TVS_SSTATUS 2
129 #define TVS_MKDIR 0x10
131 #define CHK_FETCH 0x10
132 #define CHK_FETCHDATA 0x10
133 #define CHK_FETCHACL 0x11
134 #define CHK_FETCHSTATUS 0x12
135 #define CHK_STOREDATA 0x00
136 #define CHK_STOREACL 0x01
137 #define CHK_STORESTATUS 0x02
139 #define OWNERREAD 0400
140 #define OWNERWRITE 0200
141 #define OWNEREXEC 0100
142 #ifdef USE_GROUP_PERMS
143 #define GROUPREAD 0040
144 #define GROUPWRITE 0020
145 #define GROUPREXEC 0010
148 /* The following errors were not defined in NT. They are given unique
149 * names here to avoid any potential collision.
151 #define FSERR_ELOOP 90
152 #define FSERR_EOPNOTSUPP 122
153 #define FSERR_ECONNREFUSED 130
155 #define NOTACTIVECALL 0
158 #define CREATE_SGUID_ADMIN_ONLY 1
160 extern struct afsconf_dir *confDir;
161 extern afs_int32 dataVersionHigh;
164 static struct AFSCallStatistics AFSCallStats;
165 #if FS_STATS_DETAILED
166 struct fs_stats_FullPerfStats afs_FullPerfStats;
167 extern int AnonymousID;
168 #endif /* FS_STATS_DETAILED */
169 #if TRANSARC_VOL_STATS
170 static const char nullString[] = "";
171 #endif /* TRANSARC_VOL_STATS */
174 afs_int32 NothingYet;
177 struct afs_FSStats afs_fsstats;
179 void ResetDebug(), SetDebug(), Terminate();
184 afs_int32 BlocksSpare = 1024; /* allow 1 MB overruns */
186 extern afs_int32 implicitAdminRights;
187 extern afs_int32 readonlyServer;
190 * Externals used by the xstat code.
192 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
193 extern int CEs, CEBlocks;
195 extern int HTs, HTBlocks;
197 #ifdef AFS_SGI_XFS_IOPS_ENV
198 #include <afs/xfsattrs.h>
199 static int GetLinkCount(Volume *avp, struct stat *astat)
201 if (!strcmp("xfs", astat->st_fstype)) {
202 return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
205 return astat->st_nlink;
208 #define GetLinkCount(V, S) (S)->st_nlink
211 afs_int32 SpareComp(Volume *avolp)
213 register afs_int32 temp;
217 temp = V_maxquota(avolp);
219 /* no matter; doesn't check in this case */
223 temp = (temp * PctSpare) / 100;
236 * Set the volume synchronization parameter for this volume. If it changes,
237 * the Cache Manager knows that the volume must be purged from the stat cache.
239 static void SetVolumeSync(register struct AFSVolSync *async,
240 register Volume *avol)
243 /* date volume instance was created */
246 async->spare1 = avol->header->diskstuff.creationDate;
259 * Note that this function always returns a held host, so
260 * that CallPostamble can block without the host's disappearing.
261 * Call returns rx connection in passed in *tconn
263 static int CallPreamble(register struct rx_call *acall, int activecall,
264 struct rx_connection **tconn)
267 struct client *tclient;
272 ViceLog (0, ("CallPreamble: unexpected null tconn!\n"));
275 *tconn = rx_ConnectionOf(acall);
279 tclient = h_FindClient_r(*tconn);
280 if (tclient->prfail == 1) { /* couldn't get the CPS */
282 h_ReleaseClient_r(tclient);
283 ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
287 retry_flag=0; /* Retry once */
289 /* Take down the old connection and re-read the key file */
290 ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
292 code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
295 h_ReleaseClient_r(tclient);
297 ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
301 tclient->prfail = 2; /* Means re-eval client's cps */
302 h_ReleaseClient_r(tclient);
306 thost = tclient->host;
307 tclient->LastCall = thost->LastCall = FT_ApproxTime();
308 if (activecall) /* For all but "GetTime" calls */
309 thost->ActiveCall = thost->LastCall;
312 if (thost->hostFlags & HOSTDELETED) {
313 ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
314 code = VBUSY; /* raced, so retry */
316 else if (thost->hostFlags & VENUSDOWN) {
317 if (BreakDelayedCallBacks_r(thost)) {
318 ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP. Possible network or routing failure.\n",
319 afs_inet_ntoa_r(thost->host, hoststr)));
320 if ( MultiProbeAlternateAddress_r (thost) ) {
321 ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
322 afs_inet_ntoa_r(thost->host, hoststr), thost->port));
325 ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
326 afs_inet_ntoa_r(thost->host, hoststr), thost->port));
327 if (BreakDelayedCallBacks_r(thost)) {
328 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP. Possible network or routing failure.\n",
329 afs_inet_ntoa_r(thost->host, hoststr)));
338 h_ReleaseClient_r(tclient);
346 static void CallPostamble(register struct rx_connection *aconn)
349 struct client *tclient;
352 tclient = h_FindClient_r(aconn);
353 thost = tclient->host;
354 h_ReleaseClient_r(tclient);
361 * Returns the volume and vnode pointers associated with file Fid; the lock
362 * type on the vnode is set to lock. Note that both volume/vnode's ref counts
363 * are incremented and they must be eventualy released.
366 CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock)
370 static struct timeval restartedat = {0,0};
372 if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
374 if ((*volptr) == 0) {
379 *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
384 if ((errorCode == VOFFLINE) && (VInit < 2)) {
385 /* The volume we want may not be attached yet because
386 * the volume initialization is not yet complete.
387 * We can do several things:
388 * 1. return -1, which will cause users to see
389 * "connection timed out". This is more or
390 * less the same as always, except that the servers
391 * may appear to bounce up and down while they
392 * are actually restarting.
393 * 2. return VBUSY which will cause clients to
394 * sleep and retry for 6.5 - 15 minutes, depending
395 * on what version of the CM they are running. If
396 * the file server takes longer than that interval
397 * to attach the desired volume, then the application
398 * will see an ENODEV or EIO. This approach has
399 * the advantage that volumes which have been attached
400 * are immediately available, it keeps the server's
401 * immediate backlog low, and the call is interruptible
402 * by the user. Users see "waiting for busy volume."
403 * 3. sleep here and retry. Some people like this approach
404 * because there is no danger of seeing errors. However,
405 * this approach only works with a bounded number of
406 * clients, since the pending queues will grow without
407 * stopping. It might be better to find a way to take
408 * this call and stick it back on a queue in order to
409 * recycle this thread for a different request.
410 * 4. Return a new error code, which new cache managers will
411 * know enough to interpret as "sleep and retry", without
412 * the upper bound of 6-15 minutes that is imposed by the
413 * VBUSY handling. Users will see "waiting for
414 * busy volume," so they know that something is
415 * happening. Old cache managers must be able to do
416 * something reasonable with this, for instance, mark the
417 * server down. Fortunately, any error code < 0
418 * will elicit that behavior. See #1.
419 * 5. Some combination of the above. I like doing #2 for 10
420 * minutes, followed by #4. 3.1b and 3.2 cache managers
421 * will be fine as long as the restart period is
422 * not longer than 6.5 minutes, otherwise they may
423 * return ENODEV to users. 3.3 cache managers will be
424 * fine for 10 minutes, then will return
425 * ETIMEDOUT. 3.4 cache managers will just wait
426 * until the call works or fails definitively.
427 * NB. The problem with 2,3,4,5 is that old clients won't
428 * fail over to an alternate read-only replica while this
429 * server is restarting. 3.4 clients will fail over right away.
431 if (restartedat.tv_sec == 0) {
432 /* I'm not really worried about when we restarted, I'm */
433 /* just worried about when the first VBUSY was returned. */
434 TM_GetTimeOfDay(&restartedat, 0);
439 TM_GetTimeOfDay(&now, 0);
440 if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
444 return (VRESTARTING);
448 /* allow read operations on busy volume */
449 else if(errorCode==VBUSY && lock==READ_LOCK) {
460 *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
463 if ((*vptr)->disk.uniquifier != fid->Unique) {
464 VPutVnode(&fileCode, *vptr);
465 assert(fileCode == 0);
467 return(VNOVNODE); /* return the right error code, at least */
473 * This routine returns the ACL associated with the targetptr. If the
474 * targetptr isn't a directory, we access its parent dir and get the ACL
475 * thru the parent; in such case the parent's vnode is returned in
479 SetAccessList(Vnode **targetptr,
481 struct acl_accessList **ACL,
487 if ((*targetptr)->disk.type == vDirectory) {
489 *ACL = VVnodeACL(*targetptr);
490 *ACLSize = VAclSize(*targetptr);
499 parentvnode = (*targetptr)->disk.parent;
500 VPutVnode(&errorCode,*targetptr);
502 if (errorCode) return(errorCode);
503 *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
504 if (errorCode) return(errorCode);
505 *ACL = VVnodeACL(*parent);
506 *ACLSize = VAclSize(*parent);
507 if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
509 if ((*targetptr)->disk.parent != parentvnode) {
510 VPutVnode(&errorCode, *parent);
512 if (errorCode) return(errorCode);
521 * Compare the directory's ACL with the user's access rights in the client
522 * connection and return the user's and everybody else's access permissions
523 * in rights and anyrights, respectively
526 GetRights (struct client *client,
527 struct acl_accessList *ACL,
529 afs_int32 *anyrights)
531 extern prlist SystemAnyUserCPS;
532 afs_int32 hrights = 0;
535 if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
537 ViceLog(0,("CheckRights failed\n"));
541 acl_CheckRights(ACL, &client->CPS, rights);
543 /* wait if somebody else is already doing the getCPS call */
545 while ( client->host->hostFlags & HCPS_INPROGRESS )
547 client->host->hostFlags |= HCPS_WAITING; /* I am waiting */
548 #ifdef AFS_PTHREAD_ENV
549 pthread_cond_wait(&client->host->cond, &host_glock_mutex);
550 #else /* AFS_PTHREAD_ENV */
551 if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
552 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
553 #endif /* AFS_PTHREAD_ENV */
556 if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
557 ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
559 acl_CheckRights(ACL, &client->host->hcps, &hrights);
561 /* Allow system:admin the rights given with the -implicit option */
562 if (acl_IsAMember(SystemId, &client->CPS))
563 *rights |= implicitAdminRights;
565 *anyrights |= hrights;
572 * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
573 * a System:Administrator)
576 VanillaUser(struct client *client)
578 if (acl_IsAMember(SystemId, &client->CPS))
579 return(0); /* not a system administrator, then you're "vanilla" */
586 * This unusual afs_int32-parameter routine encapsulates all volume package related
587 * operations together in a single function; it's called by almost all AFS
591 GetVolumePackage(struct rx_connection *tcon,
597 struct client **client,
600 afs_int32 *anyrights)
602 struct acl_accessList * aCL; /* Internal access List */
603 int aCLSize; /* size of the access list */
604 int errorCode = 0; /* return code to caller */
606 if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
609 if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
611 else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
614 if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
616 if (chkforDir == MustBeDIR) assert((*parent) == 0);
617 if ((errorCode = GetClient(tcon, client)) != 0)
621 assert(GetRights(*client, aCL, rights, anyrights) == 0);
622 /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
623 if ((*targetptr)->disk.type != vDirectory) {
624 /* anyuser can't be owner, so only have to worry about rights, not anyrights */
625 if ((*targetptr)->disk.owner == (*client)->ViceId)
626 (*rights) |= PRSFS_ADMINISTER;
628 (*rights) &= ~PRSFS_ADMINISTER;
630 #ifdef ADMIN_IMPLICIT_LOOKUP
631 /* admins get automatic lookup on everything */
632 if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
633 #endif /* ADMIN_IMPLICIT_LOOKUP */
636 } /*GetVolumePackage*/
640 * This is the opposite of GetVolumePackage(), and is always used at the end of
641 * AFS calls to put back all used vnodes and the volume in the proper order!
644 PutVolumePackage(Vnode *parentwhentargetnotdir,
649 int fileCode = 0; /* Error code returned by the volume package */
651 if (parentwhentargetnotdir) {
652 VPutVnode(&fileCode, parentwhentargetnotdir);
653 assert(!fileCode || (fileCode == VSALVAGE));
656 VPutVnode(&fileCode, targetptr);
657 assert(!fileCode || (fileCode == VSALVAGE));
660 VPutVnode(&fileCode, parentptr);
661 assert(!fileCode || (fileCode == VSALVAGE));
666 } /*PutVolumePackage*/
668 static int VolumeOwner (register struct client *client,
669 register Vnode *targetptr)
671 afs_int32 owner = V_owner(targetptr->volumePtr); /* get volume owner */
674 return (client->ViceId == owner);
677 * We don't have to check for host's cps since only regular
678 * viceid are volume owners.
680 return (acl_IsAMember(owner, &client->CPS));
685 static int VolumeRootVnode (Vnode *targetptr)
687 return ((targetptr->vnodeNumber == ROOTVNODE) &&
688 (targetptr->disk.uniquifier == 1));
690 } /*VolumeRootVnode*/
693 * Check if target file has the proper access permissions for the Fetch
694 * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
695 * StoreStatus) related calls
697 /* this code should probably just set a "priv" flag where all the audit events
698 * are now, and only generate the audit event once at the end of the routine,
699 * thus only generating the event if all the checks succeed, but only because
700 * of the privilege XXX
703 Check_PermissionRights(Vnode *targetptr,
704 struct client *client,
707 AFSStoreStatus *InStatus)
710 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
711 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
712 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
714 if (CallingRoutine & CHK_FETCH) {
716 if (VanillaUser(client))
718 if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client))
721 if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
722 if ( !(rights & PRSFS_LOOKUP)
723 #ifdef ADMIN_IMPLICIT_LOOKUP
724 /* grant admins fetch on all directories */
725 && VanillaUser(client)
726 #endif /* ADMIN_IMPLICIT_LOOKUP */
727 && !VolumeOwner(client, targetptr))
730 /* must have read access, or be owner and have insert access */
731 if (!(rights & PRSFS_READ) &&
732 !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
735 if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
736 #ifdef USE_GROUP_PERMS
737 if (!OWNSp(client, targetptr) &&
738 !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
739 errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
742 errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
747 * The check with the ownership below is a kludge to allow
748 * reading of files created with no read permission. The owner
749 * of the file is always allowed to read it.
751 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
752 errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
755 else /* !VanillaUser(client) && !FetchData */ {
756 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
757 AUD_INT, CallingRoutine, AUD_END);
760 else { /* a store operation */
761 if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
762 && (CallingRoutine != CHK_STOREACL)
763 && (targetptr->disk.type == vFile))
765 /* bypass protection checks on first store after a create
766 * for the creator; also prevent chowns during this time
767 * unless you are a system administrator */
768 /****** InStatus->Owner && UnixModeBits better be SET!! */
769 if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
772 else if (VanillaUser (client))
773 return(EPERM); /* Was EACCES */
775 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
776 AUD_INT, CallingRoutine, AUD_END);
779 if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
780 osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
781 AUD_INT, CallingRoutine, AUD_END);
784 if (readonlyServer) {
787 if (CallingRoutine == CHK_STOREACL) {
788 if (!(rights & PRSFS_ADMINISTER) &&
789 !VolumeOwner(client, targetptr)) return(EACCES);
791 else { /* store data or status */
792 /* watch for chowns and chgrps */
793 if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
796 else if (VanillaUser (client))
797 return(EPERM); /* Was EACCES */
799 osi_audit(PrivilegeEvent, 0,
800 AUD_INT, (client ? client->ViceId : 0),
801 AUD_INT, CallingRoutine, AUD_END);
803 /* must be sysadmin to set suid/sgid bits */
804 if ((InStatus->Mask & AFS_SETMODE) &&
806 (InStatus->UnixModeBits & 0xc00) != 0) {
808 (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
812 if (VanillaUser(client))
814 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
815 AUD_INT, CallingRoutine, AUD_END);
817 if (CallingRoutine == CHK_STOREDATA) {
820 if (!(rights & PRSFS_WRITE))
822 /* Next thing is tricky. We want to prevent people
823 * from writing files sans 0200 bit, but we want
824 * creating new files with 0444 mode to work. We
825 * don't check the 0200 bit in the "you are the owner"
826 * path above, but here we check the bit. However, if
827 * you're a system administrator, we ignore the 0200
828 * bit anyway, since you may have fchowned the file,
830 #ifdef USE_GROUP_PERMS
831 if ((targetptr->disk.type == vFile)
832 && VanillaUser(client)) {
833 if (!OWNSp(client, targetptr) &&
834 !acl_IsAMember(targetptr->disk.owner,
836 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
839 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
844 if ((targetptr->disk.type != vDirectory)
845 && (!(targetptr->disk.modeBits & OWNERWRITE)))
848 if (VanillaUser(client))
850 else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
851 AUD_INT, CallingRoutine, AUD_END);
853 else { /* a status store */
856 if (targetptr->disk.type == vDirectory) {
857 if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
860 else { /* a file or symlink */
861 if (!(rights & PRSFS_WRITE)) return(EACCES);
870 } /*Check_PermissionRights*/
874 * The Access List information is converted from its internal form in the
875 * target's vnode buffer (or its parent vnode buffer if not a dir), to an
876 * external form and returned back to the caller, via the AccessList
880 RXFetch_AccessList(Vnode *targetptr,
881 Vnode *parentwhentargetnotdir,
882 struct AFSOpaque *AccessList)
884 char * eACL; /* External access list placeholder */
886 if (acl_Externalize((targetptr->disk.type == vDirectory ?
887 VVnodeACL(targetptr) :
888 VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
891 if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
892 acl_FreeExternalACL(&eACL);
895 strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
896 AccessList->AFSOpaque_len = strlen(eACL) +1;
898 acl_FreeExternalACL(&eACL);
901 } /*RXFetch_AccessList*/
905 * The Access List information is converted from its external form in the
906 * input AccessList structure to the internal representation and copied into
907 * the target dir's vnode storage.
910 RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList)
912 struct acl_accessList * newACL; /* PlaceHolder for new access list */
914 if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
916 if ((newACL->size + 4) > VAclSize(targetptr))
918 memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
919 acl_FreeACL(&newACL);
922 } /*RXStore_AccessList*/
926 Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir,
927 struct AFSAccessList *AccessList)
929 char * eACL; /* External access list placeholder */
931 assert(acl_Externalize((targetptr->disk.type == vDirectory ?
932 VVnodeACL(targetptr) :
933 VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
934 if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
935 acl_FreeExternalACL(&eACL);
938 strcpy((char *)(AccessList->SeqBody), (char *)eACL);
939 AccessList->SeqLen = strlen(eACL) +1;
941 acl_FreeExternalACL(&eACL);
944 } /*Fetch_AccessList*/
947 * The Access List information is converted from its external form in the
948 * input AccessList structure to the internal representation and copied into
949 * the target dir's vnode storage.
952 Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList)
954 struct acl_accessList * newACL; /* PlaceHolder for new access list */
956 if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
958 if ((newACL->size + 4) > VAclSize(targetptr))
960 memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
961 acl_FreeACL(&newACL);
964 } /*Store_AccessList*/
967 /* In our current implementation, each successive data store (new file
968 * data version) creates a new inode. This function creates the new
969 * inode, copies the old inode's contents to the new one, remove the old
970 * inode (i.e. decrement inode count -- if it's currently used the delete
971 * will be delayed), and modify some fields (i.e. vnode's
972 * disk.inodeNumber and cloned)
974 #define COPYBUFFSIZE 8192
975 static int CopyOnWrite(Vnode *targetptr, Volume *volptr)
977 Inode ino, nearInode;
980 register int size, length;
983 int rc; /* return code */
984 IHandle_t *newH; /* Use until finished copying, then cp to vnode.*/
985 FdHandle_t *targFdP; /* Source Inode file handle */
986 FdHandle_t *newFdP; /* Dest Inode file handle */
988 if (targetptr->disk.type == vDirectory) DFlush(); /* just in case? */
990 size = targetptr->disk.length;
991 buff = (char *)malloc(COPYBUFFSIZE);
996 ino = VN_GET_INO(targetptr);
997 assert(VALID_INO(ino));
998 targFdP = IH_OPEN(targetptr->handle);
999 if (targFdP == NULL) {
1001 ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc));
1003 VTakeOffline (volptr);
1007 nearInode = VN_GET_INO(targetptr);
1008 ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1009 VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr),
1010 targetptr->vnodeNumber, targetptr->disk.uniquifier,
1011 (int)targetptr->disk.dataVersion);
1012 if (!VALID_INO(ino))
1014 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));
1019 IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1020 newFdP = IH_OPEN(newH);
1021 assert(newFdP != NULL);
1024 if (size > COPYBUFFSIZE) { /* more than a buffer */
1025 length = COPYBUFFSIZE;
1026 size -= COPYBUFFSIZE;
1031 rdlen = FDH_READ(targFdP, buff, length);
1032 if (rdlen == length)
1033 wrlen = FDH_WRITE(newFdP, buff, length);
1036 /* Callers of this function are not prepared to recover
1037 * from error that put the filesystem in an inconsistent
1038 * state. Make sure that we force the volume off-line if
1039 * we some error other than ENOSPC - 4.29.99)
1041 * In case we are unable to write the required bytes, and the
1042 * error code indicates that the disk is full, we roll-back to
1043 * the initial state.
1045 if((rdlen != length) || (wrlen != length))
1046 if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */
1048 ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1049 volptr->partition->name, V_id(volptr)));
1050 /* remove destination inode which was partially copied till now*/
1051 FDH_REALLYCLOSE(newFdP);
1053 FDH_REALLYCLOSE(targFdP);
1054 rc = IH_DEC(V_linkHandle(volptr), ino,
1055 V_parentId(volptr));
1057 ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1059 volptr->partition->name));
1060 VTakeOffline (volptr);
1066 ViceLog(0,("CopyOnWrite failed: volume %u in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1067 V_id(volptr), volptr->partition->name, length,
1068 rdlen, wrlen, errno));
1069 #ifdef FAST_RESTART /* if running in no-salvage, don't core the server */
1070 ViceLog(0,("CopyOnWrite failed: taking volume offline\n"));
1071 #else /* Avoid further corruption and try to get a core. */
1074 /* Decrement this inode so salvager doesn't find it. */
1075 FDH_REALLYCLOSE(newFdP);
1077 FDH_REALLYCLOSE(targFdP);
1078 rc = IH_DEC(V_linkHandle(volptr), ino,
1079 V_parentId(volptr));
1081 VTakeOffline (volptr);
1084 #ifndef AFS_PTHREAD_ENV
1086 #endif /* !AFS_PTHREAD_ENV */
1088 FDH_REALLYCLOSE(targFdP);
1089 rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1090 V_parentId(volptr)) ;
1092 IH_RELEASE(targetptr->handle);
1094 rc = FDH_SYNC(newFdP);
1097 targetptr->handle = newH;
1098 VN_SET_INO(targetptr, ino);
1099 targetptr->disk.cloned = 0;
1100 /* Internal change to vnode, no user level change to volume - def 5445 */
1101 targetptr->changed_oldTime = 1;
1103 return 0; /* success */
1108 * Common code to handle with removing the Name (file when it's called from
1109 * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1110 * given directory, parentptr.
1114 DeleteTarget(Vnode *parentptr,
1122 DirHandle childdir; /* Handle for dir package I/O */
1126 /* watch for invalid names */
1127 if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1129 if (parentptr->disk.cloned)
1131 ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1132 if ((errorCode = CopyOnWrite(parentptr, volptr)))
1134 ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode));
1139 /* check that the file is in the directory */
1140 SetDirHandle(dir, parentptr);
1141 if (Lookup(dir, Name, fileFid))
1143 fileFid->Volume = V_id(volptr);
1145 /* just-in-case check for something causing deadlock */
1146 if (fileFid->Vnode == parentptr->vnodeNumber)
1149 *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1153 if (ChkForDir == MustBeDIR) {
1154 if ((*targetptr)->disk.type != vDirectory)
1156 } else if ((*targetptr)->disk.type == vDirectory)
1159 /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/
1161 * If the uniquifiers dont match then instead of asserting
1162 * take the volume offline and return VSALVAGE
1164 if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) {
1165 VTakeOffline(volptr);
1166 errorCode = VSALVAGE;
1170 if (ChkForDir == MustBeDIR) {
1171 SetDirHandle(&childdir, *targetptr);
1172 if (IsEmpty(&childdir) != 0)
1175 (*targetptr)->delete = 1;
1176 } else if ((--(*targetptr)->disk.linkCount) == 0)
1177 (*targetptr)->delete = 1;
1178 if ((*targetptr)->delete) {
1179 if (VN_GET_INO(*targetptr)) {
1181 IH_REALLYCLOSE((*targetptr)->handle);
1182 errorCode = IH_DEC(V_linkHandle(volptr),
1183 VN_GET_INO(*targetptr),
1184 V_parentId(volptr));
1185 IH_RELEASE((*targetptr)->handle);
1186 if (errorCode == -1) {
1187 ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n",
1188 PrintInode(NULL, VN_GET_INO(*targetptr)),
1191 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
1193 if (errno != ENOENT)
1196 ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1198 VTakeOffline(volptr);
1205 VN_SET_INO(*targetptr, (Inode)0);
1206 VAdjustDiskUsage(&errorCode, volptr,
1207 -(int)nBlocks((*targetptr)->disk.length), 0);
1210 (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
1212 code = Delete(dir,(char *) Name);
1214 ViceLog(0, ("Error %d deleting %s\n", code,
1215 (((*targetptr)->disk.type== Directory)?"directory":"file")));
1216 ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1218 VTakeOffline(volptr);
1219 if (!errorCode) errorCode = code;
1229 * This routine updates the parent directory's status block after the
1230 * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1231 * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1235 Update_ParentVnodeStatus(Vnode *parentptr,
1240 #if FS_STATS_DETAILED
1241 char a_inSameNetwork
1242 #endif /* FS_STATS_DETAILED */
1245 afs_uint32 newlength; /* Holds new directory length */
1247 #if FS_STATS_DETAILED
1248 Date currDate; /*Current date*/
1249 int writeIdx; /*Write index to bump*/
1250 int timeIdx; /*Authorship time index to bump*/
1251 #endif /* FS_STATS_DETAILED */
1253 parentptr->disk.dataVersion++;
1254 newlength = Length(dir);
1256 * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1257 * (create, symlink, link, makedir) so we need to check if we have enough space
1258 * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1259 * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1261 if (nBlocks(newlength) != nBlocks(parentptr->disk.length))
1262 VAdjustDiskUsage(&errorCode, volptr,
1263 (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)),
1264 (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)));
1265 parentptr->disk.length = newlength;
1267 #if FS_STATS_DETAILED
1269 * Update directory write stats for this volume. Note that the auth
1270 * counter is located immediately after its associated ``distance''
1273 if (a_inSameNetwork)
1274 writeIdx = VOL_STATS_SAME_NET;
1276 writeIdx = VOL_STATS_DIFF_NET;
1277 V_stat_writes(volptr, writeIdx)++;
1278 if (author != AnonymousID) {
1279 V_stat_writes(volptr, writeIdx+1)++;
1283 * Update the volume's authorship information in response to this
1284 * directory operation. Get the current time, decide to which time
1285 * slot this operation belongs, and bump the appropriate slot.
1287 currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1288 timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1289 currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1290 currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1291 currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1292 currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1293 VOL_STATS_TIME_IDX_5);
1294 if (parentptr->disk.author == author) {
1295 V_stat_dirSameAuthor(volptr, timeIdx)++;
1298 V_stat_dirDiffAuthor(volptr, timeIdx)++;
1300 #endif /* FS_STATS_DETAILED */
1302 parentptr->disk.author = author;
1303 parentptr->disk.linkCount = linkcount;
1304 parentptr->disk.unixModifyTime = FT_ApproxTime(); /* This should be set from CLIENT!! */
1305 parentptr->disk.serverModifyTime = FT_ApproxTime();
1306 parentptr->changed_newTime = 1; /* vnode changed, write it back. */
1311 * Update the target file's (or dir's) status block after the specified
1312 * operation is complete. Note that some other fields maybe updated by
1313 * the individual module.
1316 /* XXX INCOMPLETE - More attention is needed here! */
1318 Update_TargetVnodeStatus(Vnode *targetptr,
1320 struct client *client,
1321 AFSStoreStatus *InStatus,
1326 #if FS_STATS_DETAILED
1327 Date currDate; /*Current date*/
1328 int writeIdx; /*Write index to bump*/
1329 int timeIdx; /*Authorship time index to bump*/
1330 #endif /* FS_STATS_DETAILED */
1332 if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR)) { /* initialize new file */
1333 targetptr->disk.parent = parentptr->vnodeNumber;
1334 targetptr->disk.length = length;
1335 /* targetptr->disk.group = 0; save some cycles */
1336 targetptr->disk.modeBits = 0777;
1337 targetptr->disk.owner = client->ViceId;
1338 targetptr->disk.dataVersion = 0 ; /* consistent with the client */
1339 targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1340 /* the inode was created in Alloc_NewVnode() */
1343 #if FS_STATS_DETAILED
1345 * Update file write stats for this volume. Note that the auth
1346 * counter is located immediately after its associated ``distance''
1349 if (client->InSameNetwork)
1350 writeIdx = VOL_STATS_SAME_NET;
1352 writeIdx = VOL_STATS_DIFF_NET;
1353 V_stat_writes(volptr, writeIdx)++;
1354 if (client->ViceId != AnonymousID) {
1355 V_stat_writes(volptr, writeIdx+1)++;
1359 * We only count operations that DON'T involve creating new objects
1360 * (files, symlinks, directories) or simply setting status as
1361 * authorship-change operations.
1363 if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1365 * Update the volume's authorship information in response to this
1366 * file operation. Get the current time, decide to which time
1367 * slot this operation belongs, and bump the appropriate slot.
1369 currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1370 timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1371 currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1372 currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1373 currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1374 currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1375 VOL_STATS_TIME_IDX_5);
1376 if (targetptr->disk.author == client->ViceId) {
1377 V_stat_fileSameAuthor(volptr, timeIdx)++;
1379 V_stat_fileDiffAuthor(volptr, timeIdx)++;
1382 #endif /* FS_STATS_DETAILED */
1384 if (!(Caller & TVS_SSTATUS))
1385 targetptr->disk.author = client->ViceId;
1386 if (Caller & TVS_SDATA) {
1387 targetptr->disk.dataVersion++;
1388 if (VanillaUser(client))
1390 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1391 #ifdef CREATE_SGUID_ADMIN_ONLY
1392 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1396 if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1397 /* store status, must explicitly request to change the date */
1398 if (InStatus->Mask & AFS_SETMODTIME)
1399 targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1401 else {/* other: date always changes, but perhaps to what is specified by caller */
1402 targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime());
1404 if (InStatus->Mask & AFS_SETOWNER) {
1405 /* admin is allowed to do chmod, chown as well as chown, chmod. */
1406 if (VanillaUser(client))
1408 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1409 #ifdef CREATE_SGUID_ADMIN_ONLY
1410 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1413 targetptr->disk.owner = InStatus->Owner;
1414 if (VolumeRootVnode (targetptr)) {
1415 Error errorCode = 0; /* what should be done with this? */
1417 V_owner(targetptr->volumePtr) = InStatus->Owner;
1418 VUpdateVolume(&errorCode, targetptr->volumePtr);
1421 if (InStatus->Mask & AFS_SETMODE) {
1422 int modebits = InStatus->UnixModeBits;
1423 #define CREATE_SGUID_ADMIN_ONLY 1
1424 #ifdef CREATE_SGUID_ADMIN_ONLY
1425 if (VanillaUser(client))
1426 modebits = modebits & 0777;
1428 if (VanillaUser(client)) {
1429 targetptr->disk.modeBits = modebits;
1432 targetptr->disk.modeBits = modebits;
1434 case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1435 AUD_INT, CHK_STOREDATA, AUD_END); break;
1437 case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1438 AUD_INT, CHK_STORESTATUS, AUD_END); break;
1443 targetptr->disk.serverModifyTime = FT_ApproxTime();
1444 if (InStatus->Mask & AFS_SETGROUP)
1445 targetptr->disk.group = InStatus->Group;
1446 /* vnode changed : to be written back by VPutVnode */
1447 targetptr->changed_newTime = 1;
1449 } /*Update_TargetVnodeStatus*/
1453 * Fills the CallBack structure with the expiration time and type of callback
1454 * structure. Warning: this function is currently incomplete.
1457 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1459 /* CallBackTime could not be 0 */
1460 if (CallBackTime == 0) {
1461 ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1462 CallBack->ExpirationTime = 0;
1464 CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1465 CallBack->CallBackVersion = CALLBACK_VERSION;
1466 CallBack->CallBackType = CB_SHARED; /* The default for now */
1468 } /*SetCallBackStruct*/
1472 * Adjusts (Subtract) "length" number of blocks from the volume's disk
1473 * allocation; if some error occured (exceeded volume quota or partition
1474 * was full, or whatever), it frees the space back and returns the code.
1475 * We usually pre-adjust the volume space to make sure that there's
1476 * enough space before consuming some.
1479 AdjustDiskUsage(Volume *volptr, afs_int32 length, afs_int32 checkLength)
1484 VAdjustDiskUsage(&rc, volptr, length, checkLength);
1486 VAdjustDiskUsage(&nc, volptr, -length, 0);
1487 if (rc == VOVERQUOTA) {
1488 ViceLog(2,("Volume %u (%s) is full\n",
1489 V_id(volptr), V_name(volptr)));
1492 if (rc == VDISKFULL) {
1493 ViceLog(0,("Partition %s that contains volume %u is full\n",
1494 volptr->partition->name, V_id(volptr)));
1497 ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc));
1502 } /*AdjustDiskUsage*/
1505 * Common code that handles the creation of a new file (SAFS_CreateFile and
1506 * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1509 Alloc_NewVnode(Vnode *parentptr,
1514 struct AFSFid *OutFid,
1516 int BlocksPreallocatedForVnode)
1518 int errorCode = 0; /* Error code returned back */
1521 Inode nearInode; /* hint for inode allocation in solaris */
1523 if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1524 BlocksPreallocatedForVnode))) {
1525 ViceLog(25, ("Insufficient space to allocate %d blocks\n",
1526 BlocksPreallocatedForVnode));
1530 *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1531 if (errorCode != 0) {
1532 VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
1535 OutFid->Volume = V_id(volptr);
1536 OutFid->Vnode = (*targetptr)->vnodeNumber;
1537 OutFid->Unique = (*targetptr)->disk.uniquifier;
1539 nearInode = VN_GET_INO(parentptr); /* parent is also in same vol */
1541 /* create the inode now itself */
1542 inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1543 VPartitionPath(V_partition(volptr)), nearInode,
1544 V_id(volptr), (*targetptr)->vnodeNumber,
1545 (*targetptr)->disk.uniquifier, 1);
1547 /* error in creating inode */
1548 if (!VALID_INO(inode))
1550 ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n",
1551 (*targetptr)->volumePtr->header->diskstuff.id,
1552 (*targetptr)->vnodeNumber,
1554 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,0);
1555 (*targetptr)->delete = 1; /* delete vnode */
1558 VN_SET_INO(*targetptr, inode);
1559 IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1561 /* copy group from parent dir */
1562 (*targetptr)->disk.group = parentptr->disk.group;
1564 if (parentptr->disk.cloned)
1566 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1567 if ((errorCode = CopyOnWrite(parentptr, volptr))) /* disk full */
1569 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1570 /* delete the vnode previously allocated */
1571 (*targetptr)->delete = 1;
1572 VAdjustDiskUsage(&temp, volptr,
1573 -BlocksPreallocatedForVnode, 0);
1574 IH_REALLYCLOSE((*targetptr)->handle);
1575 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) )
1576 ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1577 volptr->partition->name,
1578 PrintInode(NULL, inode)));
1579 IH_RELEASE((*targetptr)->handle);
1585 /* add the name to the directory */
1586 SetDirHandle(dir, parentptr);
1587 if ((errorCode = Create(dir,(char *)Name, OutFid))) {
1588 (*targetptr)->delete = 1;
1589 VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
1590 IH_REALLYCLOSE((*targetptr)->handle);
1591 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1592 ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1593 volptr->partition->name,
1594 PrintInode(NULL, inode)));
1595 IH_RELEASE((*targetptr)->handle);
1601 } /*Alloc_NewVnode*/
1605 * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1609 HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType)
1611 int Time; /* Used for time */
1612 int writeVnode = targetptr->changed_oldTime; /* save original status */
1614 /* Does the caller has Lock priviledges; root extends locks, however */
1615 if (LockingType != LockExtend && !(rights & PRSFS_LOCK))
1617 targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
1618 Time = FT_ApproxTime();
1619 switch (LockingType) {
1622 if (Time > targetptr->disk.lock.lockTime)
1623 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0;
1624 Time += AFS_LOCKWAIT;
1625 if (LockingType == LockRead) {
1626 if (targetptr->disk.lock.lockCount >= 0) {
1627 ++(targetptr->disk.lock.lockCount);
1628 targetptr->disk.lock.lockTime = Time;
1629 } else return(EAGAIN);
1631 if (targetptr->disk.lock.lockCount == 0) {
1632 targetptr->disk.lock.lockCount = -1;
1633 targetptr->disk.lock.lockTime = Time;
1634 } else return(EAGAIN);
1638 Time += AFS_LOCKWAIT;
1639 if (targetptr->disk.lock.lockCount != 0)
1640 targetptr->disk.lock.lockTime = Time;
1641 else return(EINVAL);
1644 if ((--targetptr->disk.lock.lockCount) <= 0)
1645 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0;
1648 targetptr->changed_oldTime = writeVnode; /* restore old status */
1649 ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1654 /* 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. */
1657 CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode)
1661 if (!(rights & Prfs_Mode))
1663 if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE)))
1669 * If some flags (i.e. min or max quota) are set, the volume's in disk
1670 * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1671 * update, if applicable.
1674 RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus,
1675 char *Name, char *OfflineMsg, char *Motd)
1677 Error errorCode = 0;
1679 if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1680 V_minquota(volptr) = StoreVolStatus->MinQuota;
1681 if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1682 V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1683 if (strlen(OfflineMsg) > 0) {
1684 strcpy(V_offlineMessage(volptr), OfflineMsg);
1686 if (strlen(Name) > 0) {
1687 strcpy(V_name(volptr), Name);
1689 #if TRANSARC_VOL_STATS
1691 * We don't overwrite the motd field, since it's now being used
1695 if (strlen(Motd) > 0) {
1696 strcpy(V_motd(volptr), Motd);
1698 #endif /* FS_STATS_DETAILED */
1699 VUpdateVolume(&errorCode, volptr);
1702 } /*RXUpdate_VolumeStatus*/
1707 Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus,
1708 struct BBS *Name, struct BBS *OfflineMsg,
1711 Error errorCode = 0;
1713 if (StoreVolStatus->MinQuota > -1)
1714 V_minquota(volptr) = StoreVolStatus->MinQuota;
1715 if (StoreVolStatus->MaxQuota > -1)
1716 V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1717 if (OfflineMsg->SeqLen > 1)
1718 strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody);
1719 if (Name->SeqLen > 1)
1720 strcpy(V_name(volptr), Name->SeqBody);
1721 #if TRANSARC_VOL_STATS
1723 * We don't overwrite the motd field, since it's now being used
1727 if (Motd->SeqLen > 1)
1728 strcpy(V_motd(volptr), Motd->SeqBody);
1729 #endif /* FS_STATS_DETAILED */
1730 VUpdateVolume(&errorCode, volptr);
1733 } /*Update_VolumeStatus*/
1737 * Get internal volume-related statistics from the Volume disk label
1738 * structure and put it into the VolumeStatus structure, status; it's
1739 * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return
1740 * the volume status to the caller.
1743 GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg,
1744 struct BBS *motd, Volume *volptr)
1746 status->Vid = V_id(volptr);
1747 status->ParentId = V_parentId(volptr);
1748 status->Online = V_inUse(volptr);
1749 status->InService = V_inService(volptr);
1750 status->Blessed = V_blessed(volptr);
1751 status->NeedsSalvage = V_needsSalvaged(volptr);
1752 if (VolumeWriteable(volptr))
1753 status->Type = ReadWrite;
1755 status->Type = ReadOnly;
1756 status->MinQuota = V_minquota(volptr);
1757 status->MaxQuota = V_maxquota(volptr);
1758 status->BlocksInUse = V_diskused(volptr);
1759 status->PartBlocksAvail = volptr->partition->free;
1760 status->PartMaxBlocks = volptr->partition->totalUsable;
1761 strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
1762 name->SeqLen = strlen(V_name(volptr)) + 1;
1763 if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
1764 strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
1765 offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
1766 if (offMsg->SeqLen > offMsg->MaxSeqLen)
1767 offMsg->SeqLen = offMsg -> MaxSeqLen;
1769 /*Don't do anything with the motd field*/
1770 strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen);
1771 motd->SeqLen = strlen(nullString) + 1;
1773 if (motd->SeqLen > motd->MaxSeqLen)
1774 motd->SeqLen = motd -> MaxSeqLen;
1776 } /*GetVolumeStatus*/
1779 RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg,
1780 char **motd, Volume *volptr)
1784 status->Vid = V_id(volptr);
1785 status->ParentId = V_parentId(volptr);
1786 status->Online = V_inUse(volptr);
1787 status->InService = V_inService(volptr);
1788 status->Blessed = V_blessed(volptr);
1789 status->NeedsSalvage = V_needsSalvaged(volptr);
1790 if (VolumeWriteable(volptr))
1791 status->Type = ReadWrite;
1793 status->Type = ReadOnly;
1794 status->MinQuota = V_minquota(volptr);
1795 status->MaxQuota = V_maxquota(volptr);
1796 status->BlocksInUse = V_diskused(volptr);
1797 status->PartBlocksAvail = volptr->partition->free;
1798 status->PartMaxBlocks = volptr->partition->totalUsable;
1800 /* now allocate and copy these things; they're freed by the RXGEN stub */
1801 temp = strlen(V_name(volptr)) + 1;
1802 *name = malloc(temp);
1803 strcpy(*name, V_name(volptr));
1804 temp = strlen(V_offlineMessage(volptr)) + 1;
1805 *offMsg = malloc(temp);
1806 strcpy(*offMsg, V_offlineMessage(volptr));
1807 #if TRANSARC_VOL_STATS
1809 strcpy(*motd, nullString);
1811 temp = strlen(V_motd(volptr)) + 1;
1812 *motd = malloc(temp);
1813 strcpy(*motd, V_motd(volptr));
1814 #endif /* FS_STATS_DETAILED */
1816 } /*RXGetVolumeStatus*/
1820 FileNameOK(register char *aname)
1822 register afs_int32 i, tc;
1825 /* watch for @sys on the right */
1826 if (strcmp(aname+i-4, "@sys") == 0) return 0;
1828 while ((tc = *aname++)) {
1829 if (tc == '/') return 0; /* very bad character to encounter */
1831 return 1; /* file name is ok */
1836 /* Debugging tool to print Volume Statu's contents */
1838 PrintVolumeStatus(VolumeStatus *status)
1840 ViceLog(5,("Volume header contains:\n"));
1841 ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1842 status->Vid, status->ParentId, status->Online, status->InService,
1843 status->Blessed, status->NeedsSalvage));
1844 ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1845 ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1846 status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1848 } /*PrintVolumeStatus*/
1852 * This variant of symlink is expressly to support the AFS/DFS translator
1853 * and is not supported by the AFS fileserver. We just return EINVAL.
1854 * The cache manager should not generate this call to an AFS cache manager.
1856 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1857 struct AFSFid *DirFid,
1860 struct AFSStoreStatus *InStatus,
1861 struct AFSFid *OutFid,
1862 struct AFSFetchStatus *OutFidStatus,
1863 struct AFSFetchStatus *OutDirStatus,
1864 struct AFSCallBack *CallBack,
1865 struct AFSVolSync *Sync)
1870 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1871 struct ResidencyCmdInputs *Inputs,
1872 struct ResidencyCmdOutputs *Outputs)
1877 #define AFSV_BUFFERSIZE 16384
1879 static struct afs_buffer {
1880 struct afs_buffer *next;
1881 } *freeBufferList = 0;
1882 static int afs_buffersAlloced = 0;
1884 static FreeSendBuffer(register struct afs_buffer *adata)
1887 afs_buffersAlloced--;
1888 adata->next = freeBufferList;
1889 freeBufferList = adata;
1893 } /*FreeSendBuffer*/
1895 /* allocate space for sender */
1896 static char *AllocSendBuffer()
1898 register struct afs_buffer *tp;
1901 afs_buffersAlloced++;
1902 if (!freeBufferList) {
1904 return malloc(AFSV_BUFFERSIZE);
1906 tp = freeBufferList;
1907 freeBufferList = tp->next;
1911 } /*AllocSendBuffer*/
1914 * This routine returns the status info associated with the targetptr vnode
1915 * in the AFSFetchStatus structure. Some of the newer fields, such as
1916 * SegSize and Group are not yet implemented
1919 void GetStatus(Vnode *targetptr,
1920 AFSFetchStatus *status,
1922 afs_int32 anyrights,
1925 /* initialize return status from a vnode */
1926 status->InterfaceVersion = 1;
1927 status->SyncCounter = status->dataVersionHigh = status->lockCount =
1928 status->errorCode = 0;
1929 status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1930 if (targetptr->disk.type == vFile)
1931 status->FileType = File;
1932 else if (targetptr->disk.type == vDirectory)
1933 status->FileType = Directory;
1934 else if (targetptr->disk.type == vSymlink)
1935 status->FileType = SymbolicLink;
1937 status->FileType = Invalid; /*invalid type field */
1938 status->LinkCount = targetptr->disk.linkCount;
1939 status->Length_hi = 0;
1940 status->Length = targetptr->disk.length;
1941 status->DataVersion = targetptr->disk.dataVersion;
1942 status->Author = targetptr->disk.author;
1943 status->Owner = targetptr->disk.owner;
1944 status->CallerAccess = rights;
1945 status->AnonymousAccess = anyrights;
1946 status->UnixModeBits = targetptr->disk.modeBits;
1947 status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */
1948 status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
1949 status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
1950 status->ServerModTime = targetptr->disk.serverModifyTime;
1951 status->Group = targetptr->disk.group;
1952 status->lockCount = targetptr->disk.lock.lockCount;
1953 status->errorCode = 0;
1958 afs_int32 common_FetchData64 (struct rx_call *acall,
1962 struct AFSFetchStatus *OutStatus,
1963 struct AFSCallBack *CallBack,
1964 struct AFSVolSync *Sync,
1967 Vnode * targetptr = 0; /* pointer to vnode to fetch */
1968 Vnode * parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */
1969 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
1970 int errorCode = 0; /* return code to caller */
1971 int fileCode = 0; /* return code from vol package */
1972 Volume * volptr = 0; /* pointer to the volume */
1973 struct client *client; /* pointer to the client data */
1974 struct rx_connection *tcon; /* the connection we're part of */
1975 afs_int32 rights, anyrights; /* rights for this and any user */
1976 struct client *t_client; /* tmp ptr to client data */
1977 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
1978 #if FS_STATS_DETAILED
1979 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
1980 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
1981 struct timeval opStartTime,
1982 opStopTime; /* Start/stop times for RPC op*/
1983 struct timeval xferStartTime,
1984 xferStopTime; /* Start/stop times for xfer portion*/
1985 struct timeval elapsedTime; /* Transfer time */
1986 afs_int32 bytesToXfer; /* # bytes to xfer*/
1987 afs_int32 bytesXferred; /* # bytes actually xferred*/
1988 int readIdx; /* Index of read stats array to bump*/
1989 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
1992 * Set our stats pointers, remember when the RPC operation started, and
1993 * tally the operation.
1995 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
1996 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2000 TM_GetTimeOfDay(&opStartTime, 0);
2001 #endif /* FS_STATS_DETAILED */
2003 ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2004 Fid->Volume, Fid->Vnode, Fid->Unique));
2006 AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2009 if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2012 /* Get ptr to client data for user Id for logging */
2013 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2014 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2015 ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2016 Fid->Volume, Fid->Vnode, Fid->Unique,
2017 inet_ntoa(logHostAddr), t_client->ViceId));
2019 * Get volume/vnode for the fetched file; caller's access rights to
2020 * it are also returned
2022 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2023 DONTCHECK, &parentwhentargetnotdir,
2024 &client, READ_LOCK, &rights, &anyrights)))
2027 SetVolumeSync(Sync, volptr);
2029 #if FS_STATS_DETAILED
2031 * Remember that another read operation was performed.
2034 if (client->InSameNetwork)
2035 readIdx = VOL_STATS_SAME_NET;
2037 readIdx = VOL_STATS_DIFF_NET;
2038 V_stat_reads(volptr, readIdx)++;
2039 if (client->ViceId != AnonymousID) {
2040 V_stat_reads(volptr, readIdx+1)++;
2043 #endif /* FS_STATS_DETAILED */
2045 /* Check whether the caller has permission access to fetch the data */
2046 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2051 * Drop the read lock on the parent directory after saving the parent
2052 * vnode information we need to pass to GetStatus
2054 if (parentwhentargetnotdir != NULL) {
2055 tparentwhentargetnotdir = *parentwhentargetnotdir;
2056 VPutVnode(&fileCode, parentwhentargetnotdir);
2057 assert(!fileCode || (fileCode == VSALVAGE));
2058 parentwhentargetnotdir = NULL;
2061 #if FS_STATS_DETAILED
2063 * Remember when the data transfer started.
2065 TM_GetTimeOfDay(&xferStartTime, 0);
2066 #endif /* FS_STATS_DETAILED */
2068 /* actually do the data transfer */
2069 #if FS_STATS_DETAILED
2070 errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2071 &bytesToXfer, &bytesXferred);
2073 if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2075 #endif /* FS_STATS_DETAILED */
2077 #if FS_STATS_DETAILED
2079 * At this point, the data transfer is done, for good or ill. Remember
2080 * when the transfer ended, bump the number of successes/failures, and
2081 * integrate the transfer size and elapsed time into the stats. If the
2082 * operation failed, we jump to the appropriate point.
2084 TM_GetTimeOfDay(&xferStopTime, 0);
2086 (xferP->numXfers)++;
2088 (xferP->numSuccesses)++;
2091 * Bump the xfer sum by the number of bytes actually sent, NOT the
2094 tot_bytesXferred += bytesXferred;
2095 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2096 tot_bytesXferred &= 0x3FF;
2097 if (bytesXferred < xferP->minBytes)
2098 xferP->minBytes = bytesXferred;
2099 if (bytesXferred > xferP->maxBytes)
2100 xferP->maxBytes = bytesXferred;
2103 * Tally the size of the object. Note: we tally the actual size,
2104 * NOT the number of bytes that made it out over the wire.
2106 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2107 (xferP->count[0])++;
2109 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2110 (xferP->count[1])++;
2112 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2113 (xferP->count[2])++;
2115 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2116 (xferP->count[3])++;
2118 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2119 (xferP->count[4])++;
2121 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2122 (xferP->count[5])++;
2124 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2125 (xferP->count[6])++;
2127 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2128 (xferP->count[7])++;
2130 (xferP->count[8])++;
2132 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2133 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2134 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2135 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2136 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2138 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2139 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2144 * Finally, go off to tell our caller the bad news in case the
2149 #endif /* FS_STATS_DETAILED */
2151 /* write back the OutStatus from the target vnode */
2152 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2154 /* if a r/w volume, promise a callback to the caller */
2155 if (VolumeWriteable(volptr))
2156 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2158 struct AFSFid myFid;
2159 memset(&myFid, 0, sizeof(struct AFSFid));
2160 myFid.Volume = Fid->Volume;
2161 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2165 /* Update and store volume/vnode and parent vnodes back */
2166 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2167 ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2168 CallPostamble(tcon);
2170 #if FS_STATS_DETAILED
2171 TM_GetTimeOfDay(&opStopTime, 0);
2172 if (errorCode == 0) {
2174 (opP->numSuccesses)++;
2175 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2176 fs_stats_AddTo((opP->sumTime), elapsedTime);
2177 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2178 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2179 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2181 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2182 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2187 #endif /* FS_STATS_DETAILED */
2189 osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2192 } /*SRXAFS_FetchData*/
2194 afs_int32 SRXAFS_FetchData (struct rx_call *acall,
2198 struct AFSFetchStatus *OutStatus,
2199 struct AFSCallBack *CallBack,
2200 struct AFSVolSync *Sync)
2205 code = common_FetchData64 (acall, Fid, Pos, Len, OutStatus,
2210 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall,
2214 struct AFSFetchStatus *OutStatus,
2215 struct AFSCallBack *CallBack,
2216 struct AFSVolSync *Sync)
2219 afs_int32 tPos, tLen;
2221 #ifdef AFS_64BIT_ENV
2222 if (Pos + Len > 0x7fffffff)
2226 #else /* AFS_64BIT_ENV */
2227 if (Pos.high || Len.high)
2231 #endif /* AFS_64BIT_ENV */
2233 code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2238 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,
2240 struct AFSOpaque *AccessList,
2241 struct AFSFetchStatus *OutStatus,
2242 struct AFSVolSync *Sync)
2244 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2245 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2246 int errorCode = 0; /* return error code to caller */
2247 Volume * volptr = 0; /* pointer to the volume */
2248 struct client *client; /* pointer to the client data */
2249 afs_int32 rights, anyrights; /* rights for this and any user */
2250 struct rx_connection *tcon = rx_ConnectionOf(acall);
2251 struct client *t_client; /* tmp ptr to client data */
2252 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2253 #if FS_STATS_DETAILED
2254 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2255 struct timeval opStartTime,
2256 opStopTime; /* Start/stop times for RPC op*/
2257 struct timeval elapsedTime; /* Transfer time */
2260 * Set our stats pointer, remember when the RPC operation started, and
2261 * tally the operation.
2263 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2267 TM_GetTimeOfDay(&opStartTime, 0);
2268 #endif /* FS_STATS_DETAILED */
2270 ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2271 Fid->Volume, Fid->Vnode, Fid->Unique));
2273 AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2275 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2278 /* Get ptr to client data for user Id for logging */
2279 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2280 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2281 ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2282 Fid->Volume, Fid->Vnode, Fid->Unique,
2283 inet_ntoa(logHostAddr), t_client->ViceId));
2285 AccessList->AFSOpaque_len = 0;
2286 AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2289 * Get volume/vnode for the fetched file; caller's access rights to it
2292 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2293 DONTCHECK, &parentwhentargetnotdir,
2294 &client, READ_LOCK, &rights, &anyrights)))
2297 SetVolumeSync(Sync, volptr);
2299 /* Check whether we have permission to fetch the ACL */
2300 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2304 /* Get the Access List from the dir's vnode */
2305 if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2309 /* Get OutStatus back From the target Vnode */
2310 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2313 /* Update and store volume/vnode and parent vnodes back */
2314 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2315 ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2316 errorCode, AccessList->AFSOpaque_val));
2317 CallPostamble(tcon);
2319 #if FS_STATS_DETAILED
2320 TM_GetTimeOfDay(&opStopTime, 0);
2321 if (errorCode == 0) {
2323 (opP->numSuccesses)++;
2324 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2325 fs_stats_AddTo((opP->sumTime), elapsedTime);
2326 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2327 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2328 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2330 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2331 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2336 #endif /* FS_STATS_DETAILED */
2338 osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2340 } /*SRXAFS_FetchACL*/
2344 * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2345 * merged into it when possible.
2348 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2350 struct AFSFetchStatus *OutStatus,
2351 struct AFSCallBack *CallBack,
2352 struct AFSVolSync *Sync)
2354 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2355 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2356 int errorCode = 0; /* return code to caller */
2357 Volume * volptr = 0; /* pointer to the volume */
2358 struct client *client; /* pointer to the client data */
2359 afs_int32 rights, anyrights; /* rights for this and any user */
2360 struct client *t_client; /* tmp ptr to client data */
2361 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2362 struct rx_connection *tcon = rx_ConnectionOf(acall);
2364 /* Get ptr to client data for user Id for logging */
2365 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2366 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2367 ViceLog(1, ("SAFS_FetchStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
2368 Fid->Volume, Fid->Vnode, Fid->Unique,
2369 inet_ntoa(logHostAddr), t_client->ViceId));
2371 AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2374 * Get volume/vnode for the fetched file; caller's rights to it are
2377 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2378 DONTCHECK, &parentwhentargetnotdir,
2379 &client, READ_LOCK, &rights, &anyrights)))
2380 goto Bad_FetchStatus;
2382 /* set volume synchronization information */
2383 SetVolumeSync(Sync, volptr);
2385 /* Are we allowed to fetch Fid's status? */
2386 if (targetptr->disk.type != vDirectory) {
2387 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2388 CHK_FETCHSTATUS, 0))) {
2389 if (rx_GetCallAbortCode(acall) == errorCode)
2390 rx_SetCallAbortCode(acall, 0);
2391 goto Bad_FetchStatus;
2395 /* set OutStatus From the Fid */
2396 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2398 /* If a r/w volume, also set the CallBack state */
2399 if (VolumeWriteable(volptr))
2400 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2402 struct AFSFid myFid;
2403 memset(&myFid, 0, sizeof(struct AFSFid));
2404 myFid.Volume = Fid->Volume;
2405 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2409 /* Update and store volume/vnode and parent vnodes back */
2410 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2411 ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2414 } /*SAFSS_FetchStatus*/
2417 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2418 struct AFSCBFids *Fids,
2419 struct AFSBulkStats *OutStats,
2420 struct AFSCBs *CallBacks,
2421 struct AFSVolSync *Sync)
2425 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2426 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2427 int errorCode = 0; /* return code to caller */
2428 Volume * volptr = 0; /* pointer to the volume */
2429 struct client *client; /* pointer to the client data */
2430 afs_int32 rights, anyrights; /* rights for this and any user */
2431 register struct AFSFid *tfid; /* file id we're dealing with now */
2432 struct rx_connection *tcon = rx_ConnectionOf(acall);
2433 #if FS_STATS_DETAILED
2434 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2435 struct timeval opStartTime,
2436 opStopTime; /* Start/stop times for RPC op*/
2437 struct timeval elapsedTime; /* Transfer time */
2440 * Set our stats pointer, remember when the RPC operation started, and
2441 * tally the operation.
2443 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2447 TM_GetTimeOfDay(&opStartTime, 0);
2448 #endif /* FS_STATS_DETAILED */
2450 ViceLog(1, ("SAFS_BulkStatus\n"));
2452 AFSCallStats.TotalCalls++;
2455 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2456 if (nfiles <= 0) { /* Sanity check */
2458 goto Audit_and_Return;
2461 /* allocate space for return output parameters */
2462 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2463 malloc(nfiles * sizeof(struct AFSFetchStatus));
2464 OutStats->AFSBulkStats_len = nfiles;
2465 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2466 malloc(nfiles * sizeof(struct AFSCallBack));
2467 CallBacks->AFSCBs_len = nfiles;
2469 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2470 goto Bad_BulkStatus;
2472 tfid = Fids->AFSCBFids_val;
2473 for (i=0; i<nfiles; i++, tfid++) {
2475 * Get volume/vnode for the fetched file; caller's rights to it
2479 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2480 DONTCHECK, &parentwhentargetnotdir, &client,
2481 READ_LOCK, &rights, &anyrights)))
2482 goto Bad_BulkStatus;
2483 /* set volume synchronization information, but only once per call */
2485 SetVolumeSync(Sync, volptr);
2487 /* Are we allowed to fetch Fid's status? */
2488 if (targetptr->disk.type != vDirectory) {
2489 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2490 CHK_FETCHSTATUS, 0))) {
2491 if (rx_GetCallAbortCode(acall) == errorCode)
2492 rx_SetCallAbortCode(acall, 0);
2493 goto Bad_BulkStatus;
2497 /* set OutStatus From the Fid */
2498 GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2499 rights, anyrights, parentwhentargetnotdir);
2501 /* If a r/w volume, also set the CallBack state */
2502 if (VolumeWriteable(volptr))
2503 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2504 &CallBacks->AFSCBs_val[i]);
2506 struct AFSFid myFid;
2507 memset(&myFid, 0, sizeof(struct AFSFid));
2508 myFid.Volume = tfid->Volume;
2509 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2510 &CallBacks->AFSCBs_val[i]);
2513 /* put back the file ID and volume */
2514 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2515 parentwhentargetnotdir = (Vnode *) 0;
2516 targetptr = (Vnode *) 0;
2517 volptr = (Volume *) 0;
2521 /* Update and store volume/vnode and parent vnodes back */
2522 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2523 CallPostamble(tcon);
2525 #if FS_STATS_DETAILED
2526 TM_GetTimeOfDay(&opStopTime, 0);
2527 if (errorCode == 0) {
2529 (opP->numSuccesses)++;
2530 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2531 fs_stats_AddTo((opP->sumTime), elapsedTime);
2532 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2533 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2534 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2536 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2537 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2542 #endif /* FS_STATS_DETAILED */
2545 ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode));
2546 osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2549 } /*SRXAFS_BulkStatus*/
2552 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2553 struct AFSCBFids *Fids,
2554 struct AFSBulkStats *OutStats,
2555 struct AFSCBs *CallBacks,
2556 struct AFSVolSync *Sync)
2560 Vnode * targetptr = 0; /* pointer to vnode to fetch */
2561 Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2562 int errorCode = 0; /* return code to caller */
2563 Volume * volptr = 0; /* pointer to the volume */
2564 struct client *client; /* pointer to the client data */
2565 afs_int32 rights, anyrights; /* rights for this and any user */
2566 register struct AFSFid *tfid; /* file id we're dealing with now */
2567 struct rx_connection *tcon;
2568 AFSFetchStatus *tstatus;
2569 #if FS_STATS_DETAILED
2570 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2571 struct timeval opStartTime,
2572 opStopTime; /* Start/stop times for RPC op*/
2573 struct timeval elapsedTime; /* Transfer time */
2576 * Set our stats pointer, remember when the RPC operation started, and
2577 * tally the operation.
2579 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2583 TM_GetTimeOfDay(&opStartTime, 0);
2584 #endif /* FS_STATS_DETAILED */
2586 ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2588 AFSCallStats.TotalCalls++;
2591 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2592 if (nfiles <= 0) { /* Sanity check */
2594 goto Audit_and_Return;
2597 /* allocate space for return output parameters */
2598 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2599 malloc(nfiles * sizeof(struct AFSFetchStatus));
2600 OutStats->AFSBulkStats_len = nfiles;
2601 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2602 malloc(nfiles * sizeof(struct AFSCallBack));
2603 CallBacks->AFSCBs_len = nfiles;
2605 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2606 goto Bad_InlineBulkStatus;
2609 tfid = Fids->AFSCBFids_val;
2610 for (i=0; i<nfiles; i++, tfid++) {
2612 * Get volume/vnode for the fetched file; caller's rights to it
2616 GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2617 DONTCHECK, &parentwhentargetnotdir, &client,
2618 READ_LOCK, &rights, &anyrights))) {
2619 tstatus = &OutStats->AFSBulkStats_val[i];
2620 tstatus->errorCode = errorCode;
2621 parentwhentargetnotdir = (Vnode *) 0;
2622 targetptr = (Vnode *) 0;
2623 volptr = (Volume *) 0;
2627 /* set volume synchronization information, but only once per call */
2629 SetVolumeSync(Sync, volptr);
2631 /* Are we allowed to fetch Fid's status? */
2632 if (targetptr->disk.type != vDirectory) {
2633 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2634 CHK_FETCHSTATUS, 0))) {
2635 tstatus = &OutStats->AFSBulkStats_val[i];
2636 tstatus->errorCode = errorCode;
2637 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2638 parentwhentargetnotdir = (Vnode *) 0;
2639 targetptr = (Vnode *) 0;
2640 volptr = (Volume *) 0;
2645 /* set OutStatus From the Fid */
2646 GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i],
2647 rights, anyrights, parentwhentargetnotdir);
2649 /* If a r/w volume, also set the CallBack state */
2650 if (VolumeWriteable(volptr))
2651 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2652 &CallBacks->AFSCBs_val[i]);
2654 struct AFSFid myFid;
2655 memset(&myFid, 0, sizeof(struct AFSFid));
2656 myFid.Volume = tfid->Volume;
2657 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2658 &CallBacks->AFSCBs_val[i]);
2661 /* put back the file ID and volume */
2662 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2663 parentwhentargetnotdir = (Vnode *) 0;
2664 targetptr = (Vnode *) 0;
2665 volptr = (Volume *) 0;
2668 Bad_InlineBulkStatus:
2669 /* Update and store volume/vnode and parent vnodes back */
2670 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2671 CallPostamble(tcon);
2673 #if FS_STATS_DETAILED
2674 TM_GetTimeOfDay(&opStopTime, 0);
2675 if (errorCode == 0) {
2677 (opP->numSuccesses)++;
2678 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2679 fs_stats_AddTo((opP->sumTime), elapsedTime);
2680 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2681 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2682 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2684 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2685 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2690 #endif /* FS_STATS_DETAILED */
2693 ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode));
2694 osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2697 } /*SRXAFS_InlineBulkStatus*/
2700 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,
2702 struct AFSFetchStatus *OutStatus,
2703 struct AFSCallBack *CallBack,
2704 struct AFSVolSync *Sync)
2707 struct rx_connection *tcon;
2708 #if FS_STATS_DETAILED
2709 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2710 struct timeval opStartTime,
2711 opStopTime; /* Start/stop times for RPC op*/
2712 struct timeval elapsedTime; /* Transfer time */
2715 * Set our stats pointer, remember when the RPC operation started, and
2716 * tally the operation.
2718 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2722 TM_GetTimeOfDay(&opStartTime, 0);
2723 #endif /* FS_STATS_DETAILED */
2725 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2726 goto Bad_FetchStatus;
2728 code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2731 CallPostamble(tcon);
2733 #if FS_STATS_DETAILED
2734 TM_GetTimeOfDay(&opStopTime, 0);
2737 (opP->numSuccesses)++;
2738 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2739 fs_stats_AddTo((opP->sumTime), elapsedTime);
2740 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2741 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2742 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2744 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2745 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2750 #endif /* FS_STATS_DETAILED */
2752 osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2755 } /*SRXAFS_FetchStatus*/
2758 afs_int32 SRXAFS_StoreData (struct rx_call *acall,
2760 struct AFSStoreStatus *InStatus,
2763 afs_uint32 FileLength,
2764 struct AFSFetchStatus *OutStatus,
2765 struct AFSVolSync *Sync)
2767 Vnode * targetptr = 0; /* pointer to input fid */
2768 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2769 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2770 int errorCode = 0; /* return code for caller */
2771 int fileCode = 0; /* return code from vol package */
2772 Volume * volptr = 0; /* pointer to the volume header */
2773 struct client * client; /* pointer to client structure */
2774 afs_int32 rights, anyrights; /* rights for this and any user */
2775 struct client *t_client; /* tmp ptr to client data */
2776 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2777 struct rx_connection *tcon;
2778 #if FS_STATS_DETAILED
2779 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2780 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2781 struct timeval opStartTime,
2782 opStopTime; /* Start/stop times for RPC op*/
2783 struct timeval xferStartTime,
2784 xferStopTime; /* Start/stop times for xfer portion*/
2785 struct timeval elapsedTime; /* Transfer time */
2786 afs_int32 bytesToXfer; /* # bytes to xfer */
2787 afs_int32 bytesXferred; /* # bytes actually xfer */
2788 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2791 * Set our stats pointers, remember when the RPC operation started, and
2792 * tally the operation.
2794 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2795 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2800 ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2801 Fid->Volume, Fid->Vnode, Fid->Unique));
2802 TM_GetTimeOfDay(&opStartTime, 0);
2803 #endif /* FS_STATS_DETAILED */
2806 AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2809 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2812 /* Get ptr to client data for user Id for logging */
2813 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
2814 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
2815 ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2816 Fid->Volume, Fid->Vnode, Fid->Unique,
2817 inet_ntoa(logHostAddr), t_client->ViceId));
2820 * Get associated volume/vnode for the stored file; caller's rights
2823 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2824 MustNOTBeDIR, &parentwhentargetnotdir,
2825 &client, WRITE_LOCK, &rights, &anyrights))) {
2829 /* set volume synchronization information */
2830 SetVolumeSync(Sync, volptr);
2832 if ((targetptr->disk.type == vSymlink)) {
2833 /* Should we return a better error code here??? */
2838 /* Check if we're allowed to store the data */
2839 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2840 CHK_STOREDATA, InStatus))) {
2845 * Drop the read lock on the parent directory after saving the parent
2846 * vnode information we need to pass to GetStatus
2848 if (parentwhentargetnotdir != NULL) {
2849 tparentwhentargetnotdir = *parentwhentargetnotdir;
2850 VPutVnode(&fileCode, parentwhentargetnotdir);
2851 assert(!fileCode || (fileCode == VSALVAGE));
2852 parentwhentargetnotdir = NULL;
2857 #if FS_STATS_DETAILED
2859 * Remember when the data transfer started.
2861 TM_GetTimeOfDay(&xferStartTime, 0);
2862 #endif /* FS_STATS_DETAILED */
2864 /* Do the actual storing of the data */
2865 #if FS_STATS_DETAILED
2866 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2867 Pos, Length, FileLength,
2868 (InStatus->Mask & AFS_FSYNC),
2869 &bytesToXfer, &bytesXferred);
2871 errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2872 acall, Pos, Length, FileLength,
2873 (InStatus->Mask & AFS_FSYNC));
2874 if (errorCode && (!targetptr->changed_newTime))
2876 #endif /* FS_STATS_DETAILED */
2877 #if FS_STATS_DETAILED
2879 * At this point, the data transfer is done, for good or ill. Remember
2880 * when the transfer ended, bump the number of successes/failures, and
2881 * integrate the transfer size and elapsed time into the stats. If the
2882 * operation failed, we jump to the appropriate point.
2884 TM_GetTimeOfDay(&xferStopTime, 0);
2886 (xferP->numXfers)++;
2888 (xferP->numSuccesses)++;
2891 * Bump the xfer sum by the number of bytes actually sent, NOT the
2894 tot_bytesXferred += bytesXferred;
2895 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2896 tot_bytesXferred &= 0x3FF;
2897 if (bytesXferred < xferP->minBytes)
2898 xferP->minBytes = bytesXferred;
2899 if (bytesXferred > xferP->maxBytes)
2900 xferP->maxBytes = bytesXferred;
2903 * Tally the size of the object. Note: we tally the actual size,
2904 * NOT the number of bytes that made it out over the wire.
2906 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2907 (xferP->count[0])++;
2909 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2910 (xferP->count[1])++;
2912 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2913 (xferP->count[2])++;
2915 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2916 (xferP->count[3])++;
2918 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2919 (xferP->count[4])++;
2921 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2922 (xferP->count[5])++;
2924 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2925 (xferP->count[6])++;
2927 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2928 (xferP->count[7])++;
2930 (xferP->count[8])++;
2932 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2933 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2934 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2935 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2936 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2938 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2939 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2945 * Finally, go off to tell our caller the bad news in case the
2948 if (errorCode && (!targetptr->changed_newTime))
2950 #endif /* FS_STATS_DETAILED */
2952 /* Update the status of the target's vnode */
2953 Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
2956 /* Get the updated File's status back to the caller */
2957 GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2960 /* Update and store volume/vnode and parent vnodes back */
2961 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2962 ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
2964 CallPostamble(tcon);
2966 #if FS_STATS_DETAILED
2967 TM_GetTimeOfDay(&opStopTime, 0);
2968 if (errorCode == 0) {
2970 (opP->numSuccesses)++;
2971 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2972 fs_stats_AddTo((opP->sumTime), elapsedTime);
2973 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2974 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2975 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2977 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2978 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2982 #endif /* FS_STATS_DETAILED */
2984 osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2987 } /*SRXAFS_StoreData*/
2989 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,
2991 struct AFSStoreStatus *InStatus,
2994 afs_uint64 FileLength,
2995 struct AFSFetchStatus *OutStatus,
2996 struct AFSVolSync *Sync)
3001 afs_int32 tFileLength;
3003 #ifdef AFS_64BIT_ENV
3004 if (FileLength > 0x7fffffff)
3008 tFileLength = FileLength;
3009 #else /* AFS_64BIT_ENV */
3010 if (FileLength.high)
3013 tLength = Length.low;
3014 tFileLength = FileLength.low;
3015 #endif /* AFS_64BIT_ENV */
3017 code = SRXAFS_StoreData (acall, Fid, InStatus, tPos, tLength, tFileLength,
3022 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,
3024 struct AFSOpaque *AccessList,
3025 struct AFSFetchStatus *OutStatus,
3026 struct AFSVolSync *Sync)
3028 Vnode * targetptr = 0; /* pointer to input fid */
3029 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3030 int errorCode = 0; /* return code for caller */
3031 struct AFSStoreStatus InStatus; /* Input status for fid */
3032 Volume * volptr = 0; /* pointer to the volume header */
3033 struct client * client; /* pointer to client structure */
3034 afs_int32 rights, anyrights; /* rights for this and any user */
3035 struct rx_connection *tcon;
3036 struct client *t_client; /* tmp ptr to client data */
3037 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3038 #if FS_STATS_DETAILED
3039 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3040 struct timeval opStartTime,
3041 opStopTime; /* Start/stop times for RPC op*/
3042 struct timeval elapsedTime; /* Transfer time */
3045 * Set our stats pointer, remember when the RPC operation started, and
3046 * tally the operation.
3048 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3052 TM_GetTimeOfDay(&opStartTime, 0);
3053 #endif /* FS_STATS_DETAILED */
3054 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3057 /* Get ptr to client data for user Id for logging */
3058 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3059 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3060 ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3061 Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3062 inet_ntoa(logHostAddr), t_client->ViceId));
3064 AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3067 InStatus.Mask = 0; /* not storing any status */
3070 * Get associated volume/vnode for the target dir; caller's rights
3071 * are also returned.
3073 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3074 MustBeDIR, &parentwhentargetnotdir,
3075 &client, WRITE_LOCK, &rights, &anyrights))) {
3079 /* set volume synchronization information */
3080 SetVolumeSync(Sync, volptr);
3082 /* Check if we have permission to change the dir's ACL */
3083 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3084 CHK_STOREACL, &InStatus))) {
3088 /* Build and store the new Access List for the dir */
3089 if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3093 targetptr->changed_newTime = 1; /* status change of directory */
3095 /* convert the write lock to a read lock before breaking callbacks */
3096 VVnodeWriteToRead(&errorCode, targetptr);
3097 assert(!errorCode || errorCode == VSALVAGE);
3099 /* break call backs on the directory */
3100 BreakCallBack(client->host, Fid, 0);
3102 /* Get the updated dir's status back to the caller */
3103 GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3106 /* Update and store volume/vnode and parent vnodes back */
3107 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3108 ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3109 CallPostamble(tcon);
3111 #if FS_STATS_DETAILED
3112 TM_GetTimeOfDay(&opStopTime, 0);
3113 if (errorCode == 0) {
3115 (opP->numSuccesses)++;
3116 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3117 fs_stats_AddTo((opP->sumTime), elapsedTime);
3118 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3119 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3120 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3122 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3123 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3127 #endif /* FS_STATS_DETAILED */
3129 osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3132 } /*SRXAFS_StoreACL*/
3136 * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3137 * should be merged when possible.
3140 SAFSS_StoreStatus (struct rx_call *acall,
3142 struct AFSStoreStatus *InStatus,
3143 struct AFSFetchStatus *OutStatus,
3144 struct AFSVolSync *Sync)
3147 Vnode * targetptr = 0; /* pointer to input fid */
3148 Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3149 int errorCode = 0; /* return code for caller */
3150 Volume * volptr = 0; /* pointer to the volume header */
3151 struct client * client; /* pointer to client structure */
3152 afs_int32 rights, anyrights; /* rights for this and any user */
3153 struct client *t_client; /* tmp ptr to client data */
3154 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3155 struct rx_connection *tcon = rx_ConnectionOf(acall);
3157 /* Get ptr to client data for user Id for logging */
3158 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3159 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3160 ViceLog(1, ("SAFS_StoreStatus, Fid = %u.%d.%d, Host %s, Id %d\n",
3161 Fid->Volume, Fid->Vnode, Fid->Unique,
3162 inet_ntoa(logHostAddr), t_client->ViceId));
3164 AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3167 * Get volume/vnode for the target file; caller's rights to it are
3170 if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3171 DONTCHECK, &parentwhentargetnotdir,
3172 &client, WRITE_LOCK, &rights, &anyrights))) {
3173 goto Bad_StoreStatus;
3176 /* set volume synchronization information */
3177 SetVolumeSync(Sync, volptr);
3179 /* Check if the caller has proper permissions to store status to Fid */
3180 if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3181 CHK_STORESTATUS, InStatus))) {
3182 goto Bad_StoreStatus;
3185 * Check for a symbolic link; we can't chmod these (otherwise could
3186 * change a symlink to a mt pt or vice versa)
3188 if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3190 goto Bad_StoreStatus;
3193 /* Update the status of the target's vnode */
3194 Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3195 (parentwhentargetnotdir ?
3196 parentwhentargetnotdir : targetptr), volptr, 0);
3198 /* convert the write lock to a read lock before breaking callbacks */
3199 VVnodeWriteToRead(&errorCode, targetptr);
3200 assert(!errorCode || errorCode == VSALVAGE);
3202 /* Break call backs on Fid */
3203 BreakCallBack(client->host, Fid, 0);
3205 /* Return the updated status back to caller */
3206 GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3209 /* Update and store volume/vnode and parent vnodes back */
3210 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3211 ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3214 } /*SAFSS_StoreStatus*/
3217 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,
3219 struct AFSStoreStatus *InStatus,
3220 struct AFSFetchStatus *OutStatus,
3221 struct AFSVolSync *Sync)
3224 struct rx_connection *tcon;
3225 #if FS_STATS_DETAILED
3226 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3227 struct timeval opStartTime,
3228 opStopTime; /* Start/stop times for RPC op*/
3229 struct timeval elapsedTime; /* Transfer time */
3232 * Set our stats pointer, remember when the RPC operation started, and
3233 * tally the operation.
3235 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3239 TM_GetTimeOfDay(&opStartTime, 0);
3240 #endif /* FS_STATS_DETAILED */
3242 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3243 goto Bad_StoreStatus;
3245 code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3248 CallPostamble(tcon);
3250 #if FS_STATS_DETAILED
3251 TM_GetTimeOfDay(&opStopTime, 0);
3254 (opP->numSuccesses)++;
3255 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3256 fs_stats_AddTo((opP->sumTime), elapsedTime);
3257 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3258 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3259 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3261 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3262 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3267 #endif /* FS_STATS_DETAILED */
3269 osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3272 } /*SRXAFS_StoreStatus*/
3276 * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3277 * merged in when possible.
3280 SAFSS_RemoveFile (struct rx_call *acall,
3281 struct AFSFid *DirFid,
3283 struct AFSFetchStatus *OutDirStatus,
3284 struct AFSVolSync *Sync)
3286 Vnode * parentptr = 0; /* vnode of input Directory */
3287 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3288 Vnode * targetptr = 0; /* file to be deleted */
3289 Volume * volptr = 0; /* pointer to the volume header */
3290 AFSFid fileFid; /* area for Fid from the directory */
3291 int errorCode = 0; /* error code */
3292 DirHandle dir; /* Handle for dir package I/O */
3293 struct client * client; /* pointer to client structure */
3294 afs_int32 rights, anyrights; /* rights for this and any user */
3295 struct client *t_client; /* tmp ptr to client data */
3296 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3297 struct rx_connection *tcon = rx_ConnectionOf(acall);
3300 /* Get ptr to client data for user Id for logging */
3301 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3302 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3303 ViceLog(1, ("SAFS_RemoveFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3304 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3305 inet_ntoa(logHostAddr), t_client->ViceId));
3307 AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3310 * Get volume/vnode for the parent dir; caller's access rights are
3313 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3314 MustBeDIR, &parentwhentargetnotdir,
3315 &client, WRITE_LOCK, &rights, &anyrights))) {
3316 goto Bad_RemoveFile;
3318 /* set volume synchronization information */
3319 SetVolumeSync(Sync, volptr);
3321 /* Does the caller has delete (& write) access to the parent directory? */
3322 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3323 goto Bad_RemoveFile;
3326 /* Actually delete the desired file */
3327 if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3328 &fileFid, Name, MustNOTBeDIR))) {
3329 goto Bad_RemoveFile;
3332 /* Update the vnode status of the parent dir */
3333 #if FS_STATS_DETAILED
3334 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3335 parentptr->disk.linkCount, client->InSameNetwork);
3337 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3338 parentptr->disk.linkCount);
3339 #endif /* FS_STATS_DETAILED */
3341 /* Return the updated parent dir's status back to caller */
3342 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3344 /* Handle internal callback state for the parent and the deleted file */
3345 if (targetptr->disk.linkCount == 0) {
3346 /* no references left, discard entry */
3347 DeleteFileCallBacks(&fileFid);
3348 /* convert the parent lock to a read lock before breaking callbacks */
3349 VVnodeWriteToRead(&errorCode, parentptr);
3350 assert(!errorCode || errorCode == VSALVAGE);
3352 /* convert the parent lock to a read lock before breaking callbacks */
3353 VVnodeWriteToRead(&errorCode, parentptr);
3354 assert(!errorCode || errorCode == VSALVAGE);
3355 /* convert the target lock to a read lock before breaking callbacks */
3356 VVnodeWriteToRead(&errorCode, targetptr);
3357 assert(!errorCode || errorCode == VSALVAGE);
3358 /* tell all the file has changed */
3359 BreakCallBack(client->host, &fileFid, 1);
3362 /* break call back on the directory */
3363 BreakCallBack(client->host, DirFid, 0);
3366 /* Update and store volume/vnode and parent vnodes back */
3367 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3369 ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode));
3372 } /*SAFSS_RemoveFile*/
3375 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3376 struct AFSFid *DirFid,
3378 struct AFSFetchStatus *OutDirStatus,
3379 struct AFSVolSync *Sync)
3382 struct rx_connection *tcon;
3383 #if FS_STATS_DETAILED
3384 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3385 struct timeval opStartTime,
3386 opStopTime; /* Start/stop times for RPC op*/
3387 struct timeval elapsedTime; /* Transfer time */
3390 * Set our stats pointer, remember when the RPC operation started, and
3391 * tally the operation.
3393 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3397 TM_GetTimeOfDay(&opStartTime, 0);
3398 #endif /* FS_STATS_DETAILED */
3400 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3401 goto Bad_RemoveFile;
3403 code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3406 CallPostamble(tcon);
3408 #if FS_STATS_DETAILED
3409 TM_GetTimeOfDay(&opStopTime, 0);
3412 (opP->numSuccesses)++;
3413 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3414 fs_stats_AddTo((opP->sumTime), elapsedTime);
3415 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3416 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3417 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3419 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3420 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3425 #endif /* FS_STATS_DETAILED */
3427 osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3430 } /*SRXAFS_RemoveFile*/
3434 * This routine is called exclusively from SRXAFS_CreateFile(), and should
3435 * be merged in when possible.
3438 SAFSS_CreateFile (struct rx_call *acall,
3439 struct AFSFid *DirFid,
3441 struct AFSStoreStatus *InStatus,
3442 struct AFSFid *OutFid,
3443 struct AFSFetchStatus *OutFidStatus,
3444 struct AFSFetchStatus *OutDirStatus,
3445 struct AFSCallBack *CallBack,
3446 struct AFSVolSync *Sync)
3448 Vnode * parentptr = 0; /* vnode of input Directory */
3449 Vnode * targetptr = 0; /* vnode of the new file */
3450 Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3451 Volume * volptr = 0; /* pointer to the volume header */
3452 int errorCode = 0; /* error code */
3453 DirHandle dir; /* Handle for dir package I/O */
3454 struct client * client; /* pointer to client structure */
3455 afs_int32 rights, anyrights; /* rights for this and any user */
3456 struct client *t_client; /* tmp ptr to client data */
3457 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3458 struct rx_connection *tcon = rx_ConnectionOf(acall);
3462 /* Get ptr to client data for user Id for logging */
3463 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3464 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3465 ViceLog(1, ("SAFS_CreateFile %s, Did = %u.%d.%d, Host %s, Id %d\n",
3466 Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3467 inet_ntoa(logHostAddr), t_client->ViceId));
3469 AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3471 if (!FileNameOK(Name)) {
3473 goto Bad_CreateFile;
3477 * Get associated volume/vnode for the parent dir; caller long are
3480 if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3481 MustBeDIR, &parentwhentargetnotdir,
3482 &client, WRITE_LOCK, &rights, &anyrights))) {
3483 goto Bad_CreateFile;
3486 /* set volume synchronization information */
3487 SetVolumeSync(Sync, volptr);
3489 /* Can we write (and insert) onto the parent directory? */
3490 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3491 goto Bad_CreateFile;
3493 /* get a new vnode for the file to be created and set it up */
3494 if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3495 Name, OutFid, vFile, nBlocks(0)))) {
3496 goto Bad_CreateFile;
3499 /* update the status of the parent vnode */
3500 #if FS_STATS_DETAILED
3501 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3502 parentptr->disk.linkCount, client->InSameNetwork);
3504 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3505 parentptr->disk.linkCount);
3506 #endif /* FS_STATS_DETAILED */
3508 /* update the status of the new file's vnode */
3509 Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3510 parentptr, volptr, 0);
3512 /* set up the return status for the parent dir and the newly created file */
3513 GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3514 GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3516 /* convert the write lock to a read lock before breaking callbacks */
3517 VVnodeWriteToRead(&errorCode, parentptr);
3518 assert(!errorCode || errorCode == VSALVAGE);
3520 /* break call back on parent dir */
3521 BreakCallBack(client->host, DirFid, 0);
3523 /* Return a callback promise for the newly created file to the caller */
3524 SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3527 /* Update and store volume/vnode and parent vnodes back */
3528 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3530 ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode));
3533 } /*SAFSS_CreateFile*/
3536 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3537 struct AFSFid *DirFid,
3539 struct AFSStoreStatus *InStatus,
3540 struct AFSFid *OutFid,
3541 struct AFSFetchStatus *OutFidStatus,
3542 struct AFSFetchStatus *OutDirStatus,
3543 struct AFSCallBack *CallBack,
3544 struct AFSVolSync *Sync)
3547 struct rx_connection *tcon;
3548 #if FS_STATS_DETAILED
3549 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3550 struct timeval opStartTime,
3551 opStopTime; /* Start/stop times for RPC op*/
3552 struct timeval elapsedTime; /* Transfer time */
3555 * Set our stats pointer, remember when the RPC operation started, and
3556 * tally the operation.
3558 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3562 TM_GetTimeOfDay(&opStartTime, 0);
3563 #endif /* FS_STATS_DETAILED */
3565 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3566 goto Bad_CreateFile;
3568 code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3569 OutFidStatus, OutDirStatus, CallBack, Sync);
3572 CallPostamble(tcon);
3574 #if FS_STATS_DETAILED
3575 TM_GetTimeOfDay(&opStopTime, 0);
3578 (opP->numSuccesses)++;
3579 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3580 fs_stats_AddTo((opP->sumTime), elapsedTime);
3581 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3582 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3583 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3585 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3586 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3590 #endif /* FS_STATS_DETAILED */
3592 osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3595 } /*SRXAFS_CreateFile*/
3599 * This routine is called exclusively from SRXAFS_Rename(), and should be
3600 * merged in when possible.
3603 SAFSS_Rename (struct rx_call *acall,
3604 struct AFSFid *OldDirFid,
3606 struct AFSFid *NewDirFid,
3608 struct AFSFetchStatus *OutOldDirStatus,
3609 struct AFSFetchStatus *OutNewDirStatus,
3610 struct AFSVolSync *Sync)
3612 Vnode * oldvptr = 0; /* vnode of the old Directory */
3613 Vnode * newvptr = 0; /* vnode of the new Directory */
3614 Vnode * fileptr = 0; /* vnode of the file to move */
3615 Vnode * newfileptr = 0; /* vnode of the file to delete */
3616 Vnode * testvptr = 0; /* used in directory tree walk */
3617 Vnode * parent = 0; /* parent for use in SetAccessList */
3618 int errorCode = 0; /* error code */
3619 int fileCode = 0; /* used when writing Vnodes */
3620 VnodeId testnode; /* used in directory tree walk */
3621 AFSFid fileFid; /* Fid of file to move */
3622 AFSFid newFileFid; /* Fid of new file */
3623 DirHandle olddir; /* Handle for dir package I/O */
3624 DirHandle newdir; /* Handle for dir package I/O */
3625 DirHandle filedir; /* Handle for dir package I/O */
3626 DirHandle newfiledir; /* Handle for dir package I/O */
3627 Volume * volptr = 0; /* pointer to the volume header */
3628 struct client * client; /* pointer to client structure */
3629 afs_int32 rights, anyrights; /* rights for this and any user */
3630 afs_int32 newrights; /* rights for this user */
3631 afs_int32 newanyrights; /* rights for any user */
3632 int doDelete; /* deleted the rename target (ref count now 0) */
3634 struct client *t_client; /* tmp ptr to client data */
3635 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3636 struct rx_connection *tcon = rx_ConnectionOf(acall);
3641 FidZero(&newfiledir);
3643 /* Get ptr to client data for user Id for logging */
3644 t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key);
3645 logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon));
3646 ViceLog(1, ("SAFS_Rename %s to %s, Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3647 OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3648 OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3650 inet_ntoa(logHostAddr), t_client->ViceId));
3652 AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3654 if (!FileNameOK(NewName)) {
3658 if (OldDirFid->Volume != NewDirFid->Volume) {
3663 if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3664 (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) ||
3665 (strlen(NewName) == 0) || (strlen(OldName) == 0) ) {
3671 if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3672 if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3673 &oldvptr, MustBeDIR, &parent,
3674 &client, WRITE_LOCK, &rights,
3679 if (OldDirFid->Vnode == NewDirFid->Vnode) {
3681 newrights = rights, newanyrights = anyrights;
3684 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3685 &newvptr, MustBeDIR, &parent,
3686 &client, WRITE_LOCK, &newrights,
3693 if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3694 &newvptr, MustBeDIR, &parent,
3695 &client, WRITE_LOCK, &newrights,
3700 if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3701 MustBeDIR, &parent, &client, WRITE_LOCK,
3702 &rights, &anyrights))) {
3708 /* set volume synchronization information */
3709 SetVolumeSync(Sync, volptr);
3711 if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3714 if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3718 /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3719 * call to CopyOnWrite returns error, it is not necessary to revert back
3720 * the effects of the first call because the contents of the volume is
3721 * not modified, it is only replicated.
3723 if (oldvptr->disk.cloned)
3725 ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n"));
3726 if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3729 SetDirHandle(&olddir, oldvptr);
3730 if (newvptr->disk.cloned)
3732 ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n"));
3733 if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3737 SetDirHandle(&newdir, newvptr);
3739 /* Lookup the file to delete its vnode */
3740 if (Lookup(&olddir, OldName, &fileFid)) {
3744 if (fileFid.Vnode == oldvptr->vnodeNumber ||
3745 fileFid.Vnode == newvptr->vnodeNumber) {
3746 errorCode = FSERR_ELOOP;
3749 fileFid.Volume = V_id(volptr);
3750 fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3751 if (errorCode != 0) {
3752 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3753 VTakeOffline (volptr);
3756 if (fileptr->disk.uniquifier != fileFid.Unique) {
3757 ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3758 VTakeOffline (volptr);
3763 if (fileptr->disk.type != vDirectory &&
3764 oldvptr != newvptr &&
3765 fileptr->disk.linkCount != 1) {
3767 * Hard links exist to this file - cannot move one of the links to
3768 * a new directory because of AFS restrictions (this is the same
3769 * reason that links cannot be made across directories, i.e.
3776 /* Lookup the new file */
3777 if (!(Lookup(&newdir, NewName, &newFileFid))) {
3778 if (readonlyServer) {
3779 errorCode = VREADONLY;
3782 if (!(newrights & PRSFS_DELETE)) {
3786 if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3787 newFileFid.Vnode == newvptr->vnodeNumber ||
3788 newFileFid.Vnode == fileFid.Vnode) {
3792 newFileFid.Volume = V_id(volptr);
3793 newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3794 if (errorCode != 0) {
3795 ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3796 VTakeOffline (volptr);
3799 if (fileptr->disk.uniquifier != fileFid.Unique) {
3800 ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3801 VTakeOffline (volptr);
3805 SetDirHandle(&newfiledir, newfileptr);
3806 /* Now check that we're moving directories over directories properly, etc.
3807 * return proper POSIX error codes:
3808 * if fileptr is a file and new is a dir: EISDIR.
3809 * if fileptr is a dir and new is a file: ENOTDIR.
3810 * Also, dir to be removed must be empty, of course.
3812 if (newfileptr->disk.type == vDirectory) {
3813 if (fileptr->disk.type != vDirectory) {
3817 if ((IsEmpty(&newfiledir))) {
3823 if (fileptr->disk.type == vDirectory) {
3824 errorCode = ENOTDIR;
3831 * ok - now we check that the old name is not above new name in the
3832 * directory structure. This is to prevent removing a subtree alltogether
3834 if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3835 for (testnode = newvptr->disk.parent; testnode != 0;) {
3836 if (testnode == oldvptr->vnodeNumber) {
3837 testnode = oldvptr->disk.parent;
3840 if ((testnode == fileptr->vnodeNumber) ||
3841 (testnode == newvptr->vnodeNumber)) {
3842 errorCode = FSERR_ELOOP;
3845 if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3846 errorCode = FSERR_ELOOP;
3849 testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3850 assert(errorCode == 0);
3851 testnode = testvptr->disk.parent;
3852 VPutVnode(&errorCode, testvptr);
3853 assert(errorCode == 0);
3856 /* Do the CopyonWrite first before modifying anything else. Copying is
3857 * required because we may have to change entries for ..
3859 if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3861 ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n"));
3862 if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3866 /* If the new name exists already, delete it and the file it points to */
3869 /* Delete NewName from its directory */
3870 code = Delete(&newdir, NewName);
3873 /* Drop the link count */
3874 newfileptr->disk.linkCount--;
3875 if (newfileptr->disk.linkCount == 0) { /* Link count 0 - delete */
3876 VAdjustDiskUsage(&errorCode, volptr,
3877 -(int)nBlocks(newfileptr->disk.length), 0);
3878 if (VN_GET_INO(newfileptr)) {
3879 IH_REALLYCLOSE(newfileptr->handle);
3880 errorCode = IH_DEC(V_linkHandle(volptr),
3881 VN_GET_INO(newfileptr),
3882 V_parentId(volptr));
3883 IH_RELEASE(newfileptr->handle);
3884 if (errorCode == -1) {
3885 ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
3886 PrintInode(NULL, VN_GET_INO(newfileptr)),
3888 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
3889 ViceLog(0, ("Do we need to fsck?"));
3892 VN_SET_INO(newfileptr, (Inode)0);
3893 newfileptr->delete = 1; /* Mark NewName vnode to delete */
3896 /* Link count did not drop to zero.
3897 * Mark NewName vnode as changed - updates stime.
3899 newfileptr->changed_newTime = 1;
3904 * If the create below fails, and the delete above worked, we have
3905 * removed the new name and not replaced it. This is not very likely,
3906 * but possible. We could try to put the old file back, but it is
3907 * highly unlikely that it would work since it would involve issuing
3910 if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
3913 /* Delete the old name */
3914 assert(Delete(&olddir,(char *) OldName) == 0);
3916 /* if the directory length changes, reflect it in the statistics */
3917 #if FS_STATS_DETAILED
3918 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
3919 oldvptr->disk.linkCount, client->InSameNetwork);
3920 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
3921 newvptr->disk.linkCount, client->InSameNetwork);
3923 Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
3924 oldvptr->disk.linkCount);
3925 Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
3926 newvptr->disk.linkCount);
3927 #endif /* FS_STATS_DETAILED */
3929 if (oldvptr == newvptr)
3930 oldvptr->disk.dataVersion--; /* Since it was bumped by 2! */
3932 fileptr->disk.parent = newvptr->vnodeNumber;
3933 fileptr->changed_newTime = 1; /* status change of moved file */
3935 /* if we are dealing with a rename of a directory */
3936 if (fileptr->disk.type == vDirectory) {
3937 assert(!fileptr->disk.cloned);
3938 SetDirHandle(&filedir, fileptr);
3939 /* fix .. to point to the correct place */
3940 Delete(&filedir, ".."); /* No assert--some directories may be bad */
3941 assert(Create(&filedir, "..", NewDirFid) == 0);
3942 fileptr->disk.dataVersion++;
3943 /* if the parent directories are different the link counts have to be */
3944 /* changed due to .. in the renamed directory */
3945 if (oldvptr != newvptr) {
3946 oldvptr->disk.linkCount--;
3947 newvptr->disk.linkCount++;
3951 /* set up return status */
3952 GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
3953 GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
3954 if (newfileptr && doDelete) {
3955 DeleteFileCallBacks(&newFileFid); /* no other references */
3960 /* convert the write locks to a read locks before breaking callbacks */
3961 VVnodeWriteToRead(&errorCode, newvptr);
3962 assert(!errorCode || errorCode == VSALVAGE);
3963 if (oldvptr != newvptr) {
3964 VVnodeWriteToRead(&errorCode, oldvptr);
3965 assert(!errorCode || errorCode == VSALVAGE);
3967 if (newfileptr && !doDelete) {
3968 /* convert the write lock to a read lock before breaking callbacks */
3969 VVnodeWriteToRead(&errorCode, newfileptr);
3970 assert(!errorCode || errorCode == VSALVAGE);
3973 /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */
3974 BreakCallBack(client->host, NewDirFid, 0);
3975 if (oldvptr != newvptr) {
3976 BreakCallBack(client->host, OldDirFid, 0);
3977 if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
3978 BreakCallBack(client->host, &fileFid, 0);
3981 /* Note: it is not necessary to break the callback */
3983 DeleteFileCallBacks(&newFileFid); /* no other references */
3985 /* other's still exist (with wrong link count) */
3986 BreakCallBack(client->host, &newFileFid, 1);
3991 VPutVnode(&fileCode, newfileptr);
3992 assert(fileCode == 0);
3994 PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
3999 FidZap(&newfiledir);
4000 ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4006 afs_int32 SRXAFS_Rename (struct rx_call *acall,
4007 struct AFSFid *OldDirFid,
4009 struct AFSFid *NewDirFid,
4011 struct AFSFetchStatus *OutOldDirStatus,
4012 struct AFSFetchStatus *OutNewDirStatus,
4013 struct AFSVolSync *Sync)
4016 struct rx_connection *tcon;
4017 #if FS_STATS_DETAILED
4018 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
4019 struct timeval opStartTime,
4020 opStopTime; /* Start/stop times for RPC op*/
4021 struct timeval elapsedTime; /* Transfer time */
4024 * Set our stats pointer, remember when the RPC operation started, and
4025 * tally the operation.
4027 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4031 TM_GetTimeOfDay(&opStartTime, 0);
4032 #endif /* FS_STATS_DETAILED */
4034 if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4037 code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4038 OutOldDirStatus, OutNewDirStatus, Sync);
4041 CallPostamble(tcon);
4043 #if FS_STATS_DETAILED
4044 TM_GetTimeOfDay(&opStopTime, 0);