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>
38 #undef SHARED /* XXX */
43 #include <sys/param.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
52 #ifndef AFS_LINUX20_ENV
54 #include <netinet/if_ether.h>
58 /* included early because of name conflict on IOPEN */
59 #include <sys/inode.h>
63 #endif /* AFS_HPUX_ENV */
67 #include <afs/assert.h>
70 #include <afs/afsint.h>
71 #include <afs/vldbint.h>
72 #include <afs/errors.h>
73 #include <afs/ihandle.h>
74 #include <afs/vnode.h>
75 #include <afs/volume.h>
76 #include <afs/ptclient.h>
77 #include <afs/ptuser.h>
78 #include <afs/prs_fs.h>
81 #include <rx/rx_globals.h>
83 #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)
86 #if !defined(AFS_NT40_ENV)
89 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
91 #include <sys/statfs.h>
92 #include <sys/lockf.h>
94 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
99 #include <afs/cellconfig.h>
100 #include <afs/keys.h>
103 #include <afs/partition.h>
104 #include "viced_prototypes.h"
107 #include "callback.h"
108 #include <afs/unified_afs.h>
109 #include <afs/audit.h>
110 #include <afs/afsutil.h>
113 extern void SetDirHandle(register DirHandle * dir, register Vnode * vnode);
114 extern void FidZap(DirHandle * file);
115 extern void FidZero(DirHandle * file);
117 #ifdef AFS_PTHREAD_ENV
118 pthread_mutex_t fileproc_glock_mutex;
119 #endif /* AFS_PTHREAD_ENV */
122 #define afs_stat stat64
123 #define afs_fstat fstat64
124 #define afs_open open64
125 #else /* !O_LARGEFILE */
126 #define afs_stat stat
127 #define afs_fstat fstat
128 #define afs_open open
129 #endif /* !O_LARGEFILE */
132 /* Useful local defines used by this module */
135 #define MustNOTBeDIR 1
139 #define TVS_SSTATUS 2
142 #define TVS_MKDIR 0x10
144 #define CHK_FETCH 0x10
145 #define CHK_FETCHDATA 0x10
146 #define CHK_FETCHACL 0x11
147 #define CHK_FETCHSTATUS 0x12
148 #define CHK_STOREDATA 0x00
149 #define CHK_STOREACL 0x01
150 #define CHK_STORESTATUS 0x02
152 #define OWNERREAD 0400
153 #define OWNERWRITE 0200
154 #define OWNEREXEC 0100
155 #ifdef USE_GROUP_PERMS
156 #define GROUPREAD 0040
157 #define GROUPWRITE 0020
158 #define GROUPREXEC 0010
161 /* The following errors were not defined in NT. They are given unique
162 * names here to avoid any potential collision.
164 #define FSERR_ELOOP 90
165 #define FSERR_EOPNOTSUPP 122
166 #define FSERR_ECONNREFUSED 130
168 #define NOTACTIVECALL 0
171 #define CREATE_SGUID_ADMIN_ONLY 1
173 extern struct afsconf_dir *confDir;
174 extern afs_int32 dataVersionHigh;
177 static struct AFSCallStatistics AFSCallStats;
178 #if FS_STATS_DETAILED
179 struct fs_stats_FullPerfStats afs_FullPerfStats;
180 extern int AnonymousID;
181 #endif /* FS_STATS_DETAILED */
182 #if OPENAFS_VOL_STATS
183 static const char nullString[] = "";
184 #endif /* OPENAFS_VOL_STATS */
187 afs_int32 NothingYet;
190 struct afs_FSStats afs_fsstats;
192 void ResetDebug(), SetDebug(), Terminate();
197 afs_int32 BlocksSpare = 1024; /* allow 1 MB overruns */
199 extern afs_int32 implicitAdminRights;
200 extern afs_int32 readonlyServer;
203 * Externals used by the xstat code.
205 extern VolPkgStats VStats;
206 extern int CEs, CEBlocks;
208 extern int HTs, HTBlocks;
210 afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
211 register struct rx_call *Call, afs_sfsize_t Pos,
212 afs_sfsize_t Len, afs_int32 Int64Mode,
213 #if FS_STATS_DETAILED
214 afs_sfsize_t * a_bytesToFetchP,
215 afs_sfsize_t * a_bytesFetchedP
216 #endif /* FS_STATS_DETAILED */
219 afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
220 struct AFSFid *Fid, struct client *client,
221 register struct rx_call *Call, afs_fsize_t Pos,
222 afs_fsize_t Length, afs_fsize_t FileLength,
224 #if FS_STATS_DETAILED
225 afs_sfsize_t * a_bytesToStoreP,
226 afs_sfsize_t * a_bytesStoredP
227 #endif /* FS_STATS_DETAILED */
230 #ifdef AFS_SGI_XFS_IOPS_ENV
231 #include <afs/xfsattrs.h>
233 GetLinkCount(Volume * avp, struct stat *astat)
235 if (!strcmp("xfs", astat->st_fstype)) {
236 return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
238 return astat->st_nlink;
241 #define GetLinkCount(V, S) (S)->st_nlink
245 SpareComp(Volume * avolp)
247 register afs_int32 temp;
251 temp = V_maxquota(avolp);
253 /* no matter; doesn't check in this case */
257 temp = (temp * PctSpare) / 100;
268 * Set the volume synchronization parameter for this volume. If it changes,
269 * the Cache Manager knows that the volume must be purged from the stat cache.
272 SetVolumeSync(register struct AFSVolSync *async, register Volume * avol)
275 /* date volume instance was created */
278 async->spare1 = avol->header->diskstuff.creationDate;
291 * Note that this function always returns a held host, so
292 * that CallPostamble can block without the host's disappearing.
293 * Call returns rx connection in passed in *tconn
296 CallPreamble(register struct rx_call *acall, int activecall,
297 struct rx_connection **tconn, struct host **ahostp)
300 struct client *tclient;
303 char hoststr[16], hoststr2[16];
304 struct ubik_client *uclient;
309 ViceLog(0, ("CallPreamble: unexpected null tconn!\n"));
312 *tconn = rx_ConnectionOf(acall);
316 tclient = h_FindClient_r(*tconn);
318 ViceLog(0, ("CallPreamble: Couldn't get CPS. Too many lockers\n"));
322 thost = tclient->host;
323 if (tclient->prfail == 1) { /* couldn't get the CPS */
325 h_ReleaseClient_r(tclient);
327 ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
331 retry_flag = 0; /* Retry once */
333 /* Take down the old connection and re-read the key file */
335 ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
336 #ifdef AFS_PTHREAD_ENV
337 uclient = (struct ubik_client *)pthread_getspecific(viced_uclient_key);
339 /* Is it still necessary to drop this? We hit the net, we should... */
343 code = hpr_Initialize(&uclient);
346 assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
349 code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
352 h_ReleaseClient_r(tclient);
355 ViceLog(0, ("CallPreamble: couldn't reconnect to ptserver\n"));
359 tclient->prfail = 2; /* Means re-eval client's cps */
360 h_ReleaseClient_r(tclient);
365 tclient->LastCall = thost->LastCall = FT_ApproxTime();
366 if (activecall) /* For all but "GetTime", "GetStats", and "GetCaps" calls */
367 thost->ActiveCall = thost->LastCall;
370 if (thost->hostFlags & HOSTDELETED) {
372 ("Discarded a packet for deleted host %s:%d\n",
373 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port)));
374 code = VBUSY; /* raced, so retry */
375 } else if ((thost->hostFlags & VENUSDOWN)
376 || (thost->hostFlags & HFE_LATER)) {
377 if (BreakDelayedCallBacks_r(thost)) {
379 ("BreakDelayedCallbacks FAILED for host %s:%d which IS UP. Connection from %s:%d. Possible network or routing failure.\n",
380 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2),
381 ntohs(rxr_PortOf(*tconn))));
382 if (MultiProbeAlternateAddress_r(thost)) {
384 ("MultiProbe failed to find new address for host %s:%d\n",
385 afs_inet_ntoa_r(thost->host, hoststr),
386 ntohs(thost->port)));
390 ("MultiProbe found new address for host %s:%d\n",
391 afs_inet_ntoa_r(thost->host, hoststr),
392 ntohs(thost->port)));
393 if (BreakDelayedCallBacks_r(thost)) {
395 ("BreakDelayedCallbacks FAILED AGAIN for host %s:%d which IS UP. Connection from %s:%d. Possible network or routing failure.\n",
396 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2),
397 ntohs(rxr_PortOf(*tconn))));
406 h_ReleaseClient_r(tclient);
416 CallPostamble(register struct rx_connection *aconn, afs_int32 ret,
420 struct client *tclient;
425 tclient = h_FindClient_r(aconn);
428 thost = tclient->host;
429 if (thost->hostFlags & HERRORTRANS)
431 h_ReleaseClient_r(tclient);
432 held = h_Held_r(thost);
435 if (ahost && ahost != thost) {
436 char hoststr[16], hoststr2[16];
437 ViceLog(0, ("CallPostamble: ahost %s:%d (%x) != thost %s:%d (%x)\n",
438 afs_inet_ntoa_r(ahost->host, hoststr), ntohs(ahost->port),
440 afs_inet_ntoa_r(thost->host, hoststr2), ntohs(thost->port),
445 ViceLog(0, ("CallPostamble: null ahost for thost %s:%d (%x)\n",
446 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port),
451 return (translate ? sys_error_to_et(ret) : ret);
455 * Returns the volume and vnode pointers associated with file Fid; the lock
456 * type on the vnode is set to lock. Note that both volume/vnode's ref counts
457 * are incremented and they must be eventualy released.
460 CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
463 afs_int32 local_errorCode, errorCode = -1;
464 static struct timeval restartedat = { 0, 0 };
466 if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
468 if ((*volptr) == 0) {
473 *volptr = VGetVolume(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
478 if ((errorCode == VOFFLINE) && (VInit < 2)) {
479 /* The volume we want may not be attached yet because
480 * the volume initialization is not yet complete.
481 * We can do several things:
482 * 1. return -1, which will cause users to see
483 * "connection timed out". This is more or
484 * less the same as always, except that the servers
485 * may appear to bounce up and down while they
486 * are actually restarting.
487 * 2. return VBUSY which will cause clients to
488 * sleep and retry for 6.5 - 15 minutes, depending
489 * on what version of the CM they are running. If
490 * the file server takes longer than that interval
491 * to attach the desired volume, then the application
492 * will see an ENODEV or EIO. This approach has
493 * the advantage that volumes which have been attached
494 * are immediately available, it keeps the server's
495 * immediate backlog low, and the call is interruptible
496 * by the user. Users see "waiting for busy volume."
497 * 3. sleep here and retry. Some people like this approach
498 * because there is no danger of seeing errors. However,
499 * this approach only works with a bounded number of
500 * clients, since the pending queues will grow without
501 * stopping. It might be better to find a way to take
502 * this call and stick it back on a queue in order to
503 * recycle this thread for a different request.
504 * 4. Return a new error code, which new cache managers will
505 * know enough to interpret as "sleep and retry", without
506 * the upper bound of 6-15 minutes that is imposed by the
507 * VBUSY handling. Users will see "waiting for
508 * busy volume," so they know that something is
509 * happening. Old cache managers must be able to do
510 * something reasonable with this, for instance, mark the
511 * server down. Fortunately, any error code < 0
512 * will elicit that behavior. See #1.
513 * 5. Some combination of the above. I like doing #2 for 10
514 * minutes, followed by #4. 3.1b and 3.2 cache managers
515 * will be fine as long as the restart period is
516 * not longer than 6.5 minutes, otherwise they may
517 * return ENODEV to users. 3.3 cache managers will be
518 * fine for 10 minutes, then will return
519 * ETIMEDOUT. 3.4 cache managers will just wait
520 * until the call works or fails definitively.
521 * NB. The problem with 2,3,4,5 is that old clients won't
522 * fail over to an alternate read-only replica while this
523 * server is restarting. 3.4 clients will fail over right away.
525 if (restartedat.tv_sec == 0) {
526 /* I'm not really worried about when we restarted, I'm */
527 /* just worried about when the first VBUSY was returned. */
528 TM_GetTimeOfDay(&restartedat, 0);
531 afs_perfstats.fs_nBusies++;
534 return (busyonrst ? VBUSY : VRESTARTING);
537 TM_GetTimeOfDay(&now, 0);
538 if ((now.tv_sec - restartedat.tv_sec) < (11 * 60)) {
541 afs_perfstats.fs_nBusies++;
544 return (busyonrst ? VBUSY : VRESTARTING);
546 return (VRESTARTING);
550 /* allow read operations on busy volume.
551 * must check local_errorCode because demand attach fs
552 * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
553 else if (local_errorCode == VBUSY && lock == READ_LOCK) {
556 } else if (errorCode)
563 *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
566 if ((*vptr)->disk.uniquifier != fid->Unique) {
567 VPutVnode(&fileCode, *vptr);
568 assert(fileCode == 0);
570 return (VNOVNODE); /* return the right error code, at least */
576 * This routine returns the ACL associated with the targetptr. If the
577 * targetptr isn't a directory, we access its parent dir and get the ACL
578 * thru the parent; in such case the parent's vnode is returned in
582 SetAccessList(Vnode ** targetptr, Volume ** volume,
583 struct acl_accessList **ACL, int *ACLSize, Vnode ** parent,
584 AFSFid * Fid, int Lock)
586 if ((*targetptr)->disk.type == vDirectory) {
588 *ACL = VVnodeACL(*targetptr);
589 *ACLSize = VAclSize(*targetptr);
597 parentvnode = (*targetptr)->disk.parent;
598 VPutVnode(&errorCode, *targetptr);
602 *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
605 *ACL = VVnodeACL(*parent);
606 *ACLSize = VAclSize(*parent);
607 if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
609 if ((*targetptr)->disk.parent != parentvnode) {
610 VPutVnode(&errorCode, *parent);
621 /* Must not be called with H_LOCK held */
623 client_CheckRights(struct client *client, struct acl_accessList *ACL,
627 ObtainReadLock(&client->lock);
628 if (client->CPS.prlist_len > 0 && !client->deleted &&
629 client->host && !(client->host->hostFlags & HOSTDELETED))
630 acl_CheckRights(ACL, &client->CPS, rights);
631 ReleaseReadLock(&client->lock);
634 /* Must not be called with H_LOCK held */
636 client_HasAsMember(struct client *client, afs_int32 id)
640 ObtainReadLock(&client->lock);
641 if (client->CPS.prlist_len > 0 && !client->deleted &&
642 client->host && !(client->host->hostFlags & HOSTDELETED))
643 code = acl_IsAMember(id, &client->CPS);
644 ReleaseReadLock(&client->lock);
649 * Compare the directory's ACL with the user's access rights in the client
650 * connection and return the user's and everybody else's access permissions
651 * in rights and anyrights, respectively
654 GetRights(struct client *client, struct acl_accessList *ACL,
655 afs_int32 * rights, afs_int32 * anyrights)
657 extern prlist SystemAnyUserCPS;
658 afs_int32 hrights = 0;
659 #ifndef AFS_PTHREAD_ENV
663 if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
664 ViceLog(0, ("CheckRights failed\n"));
669 client_CheckRights(client, ACL, rights);
671 /* wait if somebody else is already doing the getCPS call */
673 while (client->host->hostFlags & HCPS_INPROGRESS) {
674 client->host->hostFlags |= HCPS_WAITING; /* I am waiting */
675 #ifdef AFS_PTHREAD_ENV
676 pthread_cond_wait(&client->host->cond, &host_glock_mutex);
677 #else /* AFS_PTHREAD_ENV */
679 LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
680 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
681 #endif /* AFS_PTHREAD_ENV */
684 if (!client->host->hcps.prlist_len || !client->host->hcps.prlist_val) {
687 ("CheckRights: len=%u, for host=%s:%d\n",
688 client->host->hcps.prlist_len,
689 afs_inet_ntoa_r(client->host->host, hoststr),
690 ntohs(client->host->port)));
692 acl_CheckRights(ACL, &client->host->hcps, &hrights);
694 /* Allow system:admin the rights given with the -implicit option */
695 if (client_HasAsMember(client, SystemId))
696 *rights |= implicitAdminRights;
699 *anyrights |= hrights;
706 * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
707 * a System:Administrator)
710 VanillaUser(struct client *client)
712 if (client_HasAsMember(client, SystemId))
713 return (0); /* not a system administrator, then you're "vanilla" */
720 * This unusual afs_int32-parameter routine encapsulates all volume package related
721 * operations together in a single function; it's called by almost all AFS
725 GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
726 Vnode ** targetptr, int chkforDir, Vnode ** parent,
727 struct client **client, int locktype, afs_int32 * rights,
728 afs_int32 * anyrights)
730 struct acl_accessList *aCL; /* Internal access List */
731 int aCLSize; /* size of the access list */
732 int errorCode = 0; /* return code to caller */
734 if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
737 if (chkforDir == MustNOTBeDIR
738 && ((*targetptr)->disk.type == vDirectory))
740 else if (chkforDir == MustBeDIR
741 && ((*targetptr)->disk.type != vDirectory))
745 SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
746 (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
747 (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
749 if (chkforDir == MustBeDIR)
750 assert((*parent) == 0);
752 if ((errorCode = GetClient(tcon, client)) != 0)
757 GetRights(*client, aCL, rights, anyrights);
758 /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
759 if ((*targetptr)->disk.type != vDirectory) {
760 /* anyuser can't be owner, so only have to worry about rights, not anyrights */
761 if ((*targetptr)->disk.owner == (*client)->ViceId)
762 (*rights) |= PRSFS_ADMINISTER;
764 (*rights) &= ~PRSFS_ADMINISTER;
766 #ifdef ADMIN_IMPLICIT_LOOKUP
767 /* admins get automatic lookup on everything */
768 if (!VanillaUser(*client))
769 (*rights) |= PRSFS_LOOKUP;
770 #endif /* ADMIN_IMPLICIT_LOOKUP */
773 } /*GetVolumePackage */
777 * This is the opposite of GetVolumePackage(), and is always used at the end of
778 * AFS calls to put back all used vnodes and the volume in the proper order!
781 PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
782 Vnode * parentptr, Volume * volptr, struct client **client)
784 int fileCode = 0; /* Error code returned by the volume package */
786 if (parentwhentargetnotdir) {
787 VPutVnode(&fileCode, parentwhentargetnotdir);
788 assert(!fileCode || (fileCode == VSALVAGE));
791 VPutVnode(&fileCode, targetptr);
792 assert(!fileCode || (fileCode == VSALVAGE));
795 VPutVnode(&fileCode, parentptr);
796 assert(!fileCode || (fileCode == VSALVAGE));
804 } /*PutVolumePackage */
807 VolumeOwner(register struct client *client, register Vnode * targetptr)
809 afs_int32 owner = V_owner(targetptr->volumePtr); /* get volume owner */
812 return (client->ViceId == owner);
815 * We don't have to check for host's cps since only regular
816 * viceid are volume owners.
818 return (client_HasAsMember(client, owner));
824 VolumeRootVnode(Vnode * targetptr)
826 return ((targetptr->vnodeNumber == ROOTVNODE)
827 && (targetptr->disk.uniquifier == 1));
829 } /*VolumeRootVnode */
832 * Check if target file has the proper access permissions for the Fetch
833 * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
834 * StoreStatus) related calls
836 /* this code should probably just set a "priv" flag where all the audit events
837 * are now, and only generate the audit event once at the end of the routine,
838 * thus only generating the event if all the checks succeed, but only because
839 * of the privilege XXX
842 Check_PermissionRights(Vnode * targetptr, struct client *client,
843 afs_int32 rights, int CallingRoutine,
844 AFSStoreStatus * InStatus)
847 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
848 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
849 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
851 if (CallingRoutine & CHK_FETCH) {
852 if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) {
853 if (targetptr->disk.type == vDirectory
854 || targetptr->disk.type == vSymlink) {
855 if (!(rights & PRSFS_LOOKUP)
856 #ifdef ADMIN_IMPLICIT_LOOKUP
857 /* grant admins fetch on all directories */
858 && VanillaUser(client)
859 #endif /* ADMIN_IMPLICIT_LOOKUP */
860 && !VolumeOwner(client, targetptr))
863 /* must have read access, or be owner and have insert access */
864 if (!(rights & PRSFS_READ)
865 && !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
868 if (CallingRoutine == CHK_FETCHDATA
869 && targetptr->disk.type == vFile)
870 #ifdef USE_GROUP_PERMS
871 if (!OWNSp(client, targetptr)
872 && !client_HasAsMember(client, targetptr->disk.owner)) {
874 (((GROUPREAD | GROUPEXEC) & targetptr->disk.modeBits)
878 (((OWNERREAD | OWNEREXEC) & targetptr->disk.modeBits)
883 * The check with the ownership below is a kludge to allow
884 * reading of files created with no read permission. The owner
885 * of the file is always allowed to read it.
887 if ((client->ViceId != targetptr->disk.owner)
888 && VanillaUser(client))
890 (((OWNERREAD | OWNEREXEC) & targetptr->disk.
891 modeBits) ? 0 : EACCES);
893 } else { /* !VanillaUser(client) && !FetchData */
895 osi_audit(PrivilegeEvent, 0, AUD_ID,
896 (client ? client->ViceId : 0), AUD_INT, CallingRoutine,
899 } else { /* a store operation */
900 if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
901 && (CallingRoutine != CHK_STOREACL)
902 && (targetptr->disk.type == vFile)) {
903 /* bypass protection checks on first store after a create
904 * for the creator; also prevent chowns during this time
905 * unless you are a system administrator */
906 /****** InStatus->Owner && UnixModeBits better be SET!! */
907 if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
910 else if (VanillaUser(client))
911 return (EPERM); /* Was EACCES */
913 osi_audit(PrivilegeEvent, 0, AUD_ID,
914 (client ? client->ViceId : 0), AUD_INT,
915 CallingRoutine, AUD_END);
918 if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
919 osi_audit(PrivilegeEvent, 0, AUD_ID,
920 (client ? client->ViceId : 0), AUD_INT,
921 CallingRoutine, AUD_END);
923 if (readonlyServer) {
926 if (CallingRoutine == CHK_STOREACL) {
927 if (!(rights & PRSFS_ADMINISTER)
928 && !VolumeOwner(client, targetptr))
930 } else { /* store data or status */
931 /* watch for chowns and chgrps */
932 if (CHOWN(InStatus, targetptr)
933 || CHGRP(InStatus, targetptr)) {
936 else if (VanillaUser(client))
937 return (EPERM); /* Was EACCES */
939 osi_audit(PrivilegeEvent, 0, AUD_ID,
940 (client ? client->ViceId : 0), AUD_INT,
941 CallingRoutine, AUD_END);
943 /* must be sysadmin to set suid/sgid bits */
944 if ((InStatus->Mask & AFS_SETMODE) &&
946 (InStatus->UnixModeBits & 0xc00) != 0) {
948 (InStatus->UnixModeBits & (S_ISUID | S_ISGID)) != 0) {
952 if (VanillaUser(client))
955 osi_audit(PrivSetID, 0, AUD_ID,
956 (client ? client->ViceId : 0), AUD_INT,
957 CallingRoutine, AUD_END);
959 if (CallingRoutine == CHK_STOREDATA) {
962 if (!(rights & PRSFS_WRITE))
964 /* Next thing is tricky. We want to prevent people
965 * from writing files sans 0200 bit, but we want
966 * creating new files with 0444 mode to work. We
967 * don't check the 0200 bit in the "you are the owner"
968 * path above, but here we check the bit. However, if
969 * you're a system administrator, we ignore the 0200
970 * bit anyway, since you may have fchowned the file,
972 #ifdef USE_GROUP_PERMS
973 if ((targetptr->disk.type == vFile)
974 && VanillaUser(client)) {
975 if (!OWNSp(client, targetptr)
976 && !client_HasAsMember(client, targetptr->disk.owner)) {
978 ((GROUPWRITE & targetptr->disk.modeBits)
982 ((OWNERWRITE & targetptr->disk.modeBits)
987 if ((targetptr->disk.type != vDirectory)
988 && (!(targetptr->disk.modeBits & OWNERWRITE))) {
991 if (VanillaUser(client))
994 osi_audit(PrivilegeEvent, 0, AUD_ID,
995 (client ? client->ViceId : 0),
996 AUD_INT, CallingRoutine, AUD_END);
998 } else { /* a status store */
1001 if (targetptr->disk.type == vDirectory) {
1002 if (!(rights & PRSFS_DELETE)
1003 && !(rights & PRSFS_INSERT))
1005 } else { /* a file or symlink */
1006 if (!(rights & PRSFS_WRITE))
1016 } /*Check_PermissionRights */
1020 * The Access List information is converted from its internal form in the
1021 * target's vnode buffer (or its parent vnode buffer if not a dir), to an
1022 * external form and returned back to the caller, via the AccessList
1026 RXFetch_AccessList(Vnode * targetptr, Vnode * parentwhentargetnotdir,
1027 struct AFSOpaque *AccessList)
1029 char *eACL; /* External access list placeholder */
1032 ((targetptr->disk.type ==
1033 vDirectory ? VVnodeACL(targetptr) :
1034 VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
1037 if ((strlen(eACL) + 1) > AFSOPAQUEMAX) {
1038 acl_FreeExternalACL(&eACL);
1041 strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
1042 AccessList->AFSOpaque_len = strlen(eACL) + 1;
1044 acl_FreeExternalACL(&eACL);
1047 } /*RXFetch_AccessList */
1051 * The Access List information is converted from its external form in the
1052 * input AccessList structure to the internal representation and copied into
1053 * the target dir's vnode storage.
1056 RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList)
1058 struct acl_accessList *newACL; /* PlaceHolder for new access list */
1060 if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
1062 if ((newACL->size + 4) > VAclSize(targetptr))
1064 memcpy((char *)VVnodeACL(targetptr), (char *)newACL, (int)(newACL->size));
1065 acl_FreeACL(&newACL);
1068 } /*RXStore_AccessList */
1071 /* In our current implementation, each successive data store (new file
1072 * data version) creates a new inode. This function creates the new
1073 * inode, copies the old inode's contents to the new one, remove the old
1074 * inode (i.e. decrement inode count -- if it's currently used the delete
1075 * will be delayed), and modify some fields (i.e. vnode's
1076 * disk.inodeNumber and cloned)
1078 #define COPYBUFFSIZE 8192
1080 CopyOnWrite(Vnode * targetptr, Volume * volptr)
1082 Inode ino, nearInode;
1085 register afs_fsize_t size;
1086 register int length;
1088 int rc; /* return code */
1089 IHandle_t *newH; /* Use until finished copying, then cp to vnode. */
1090 FdHandle_t *targFdP; /* Source Inode file handle */
1091 FdHandle_t *newFdP; /* Dest Inode file handle */
1093 if (targetptr->disk.type == vDirectory)
1094 DFlush(); /* just in case? */
1096 VN_GET_LEN(size, targetptr);
1097 buff = (char *)malloc(COPYBUFFSIZE);
1102 ino = VN_GET_INO(targetptr);
1103 if (!VALID_INO(ino)) {
1105 VTakeOffline(volptr);
1106 ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1110 targFdP = IH_OPEN(targetptr->handle);
1111 if (targFdP == NULL) {
1114 ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n",
1115 targetptr->vnodeNumber, V_id(volptr), rc));
1117 VTakeOffline(volptr);
1121 nearInode = VN_GET_INO(targetptr);
1123 IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1124 VPartitionPath(V_partition(volptr)), nearInode,
1125 V_id(volptr), targetptr->vnodeNumber,
1126 targetptr->disk.uniquifier,
1127 (int)targetptr->disk.dataVersion);
1128 if (!VALID_INO(ino)) {
1130 ("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n",
1131 volptr->partition->name, V_id(volptr), errno));
1136 IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1137 newFdP = IH_OPEN(newH);
1138 assert(newFdP != NULL);
1141 if (size > COPYBUFFSIZE) { /* more than a buffer */
1142 length = COPYBUFFSIZE;
1143 size -= COPYBUFFSIZE;
1148 rdlen = FDH_READ(targFdP, buff, length);
1149 if (rdlen == length)
1150 wrlen = FDH_WRITE(newFdP, buff, length);
1153 /* Callers of this function are not prepared to recover
1154 * from error that put the filesystem in an inconsistent
1155 * state. Make sure that we force the volume off-line if
1156 * we some error other than ENOSPC - 4.29.99)
1158 * In case we are unable to write the required bytes, and the
1159 * error code indicates that the disk is full, we roll-back to
1160 * the initial state.
1162 if ((rdlen != length) || (wrlen != length))
1163 if ((wrlen < 0) && (errno == ENOSPC)) { /* disk full */
1165 ("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1166 volptr->partition->name, V_id(volptr)));
1167 /* remove destination inode which was partially copied till now */
1168 FDH_REALLYCLOSE(newFdP);
1170 FDH_REALLYCLOSE(targFdP);
1171 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1174 ("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1175 rc, V_id(volptr), volptr->partition->name));
1176 VTakeOffline(volptr);
1182 ("CopyOnWrite failed: volume %u in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1183 V_id(volptr), volptr->partition->name, length, rdlen,
1185 #if defined(AFS_DEMAND_ATTACH_FS)
1186 ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
1188 ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
1190 /* Decrement this inode so salvager doesn't find it. */
1191 FDH_REALLYCLOSE(newFdP);
1193 FDH_REALLYCLOSE(targFdP);
1194 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1196 VTakeOffline(volptr);
1199 #ifndef AFS_PTHREAD_ENV
1201 #endif /* !AFS_PTHREAD_ENV */
1203 FDH_REALLYCLOSE(targFdP);
1204 rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1205 V_parentId(volptr));
1207 IH_RELEASE(targetptr->handle);
1209 rc = FDH_SYNC(newFdP);
1212 targetptr->handle = newH;
1213 VN_SET_INO(targetptr, ino);
1214 targetptr->disk.cloned = 0;
1215 /* Internal change to vnode, no user level change to volume - def 5445 */
1216 targetptr->changed_oldTime = 1;
1218 return 0; /* success */
1223 * Common code to handle with removing the Name (file when it's called from
1224 * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1225 * given directory, parentptr.
1227 int DT1 = 0, DT0 = 0;
1229 DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
1230 DirHandle * dir, AFSFid * fileFid, char *Name, int ChkForDir)
1232 DirHandle childdir; /* Handle for dir package I/O */
1236 /* watch for invalid names */
1237 if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1239 if (parentptr->disk.cloned) {
1240 ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1241 if ((errorCode = CopyOnWrite(parentptr, volptr))) {
1243 ("DeleteTarget %s: CopyOnWrite failed %d\n", Name,
1249 /* check that the file is in the directory */
1250 SetDirHandle(dir, parentptr);
1251 if (Lookup(dir, Name, fileFid))
1253 fileFid->Volume = V_id(volptr);
1255 /* just-in-case check for something causing deadlock */
1256 if (fileFid->Vnode == parentptr->vnodeNumber)
1259 *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1263 if (ChkForDir == MustBeDIR) {
1264 if ((*targetptr)->disk.type != vDirectory)
1266 } else if ((*targetptr)->disk.type == vDirectory)
1269 /*assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
1271 * If the uniquifiers dont match then instead of asserting
1272 * take the volume offline and return VSALVAGE
1274 if ((*targetptr)->disk.uniquifier != fileFid->Unique) {
1275 VTakeOffline(volptr);
1277 ("Volume %u now offline, must be salvaged.\n",
1279 errorCode = VSALVAGE;
1283 if (ChkForDir == MustBeDIR) {
1284 SetDirHandle(&childdir, *targetptr);
1285 if (IsEmpty(&childdir) != 0)
1289 (*targetptr)->delete = 1;
1290 } else if ((--(*targetptr)->disk.linkCount) == 0)
1291 (*targetptr)->delete = 1;
1292 if ((*targetptr)->delete) {
1293 if (VN_GET_INO(*targetptr)) {
1295 IH_REALLYCLOSE((*targetptr)->handle);
1297 IH_DEC(V_linkHandle(volptr), VN_GET_INO(*targetptr),
1298 V_parentId(volptr));
1299 IH_RELEASE((*targetptr)->handle);
1300 if (errorCode == -1) {
1302 ("DT: inode=%s, name=%s, errno=%d\n",
1303 PrintInode(NULL, VN_GET_INO(*targetptr)), Name,
1305 if (errno != ENOENT)
1307 VTakeOffline(volptr);
1309 ("Volume %u now offline, must be salvaged.\n",
1317 VN_SET_INO(*targetptr, (Inode) 0);
1319 afs_fsize_t adjLength;
1320 VN_GET_LEN(adjLength, *targetptr);
1321 VAdjustDiskUsage(&errorCode, volptr, -(int)nBlocks(adjLength), 0);
1325 (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
1327 code = Delete(dir, (char *)Name);
1330 ("Error %d deleting %s\n", code,
1331 (((*targetptr)->disk.type ==
1332 Directory) ? "directory" : "file")));
1333 VTakeOffline(volptr);
1335 ("Volume %u now offline, must be salvaged.\n",
1348 * This routine updates the parent directory's status block after the
1349 * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1350 * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1354 Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
1355 int author, int linkcount,
1356 #if FS_STATS_DETAILED
1357 char a_inSameNetwork
1358 #endif /* FS_STATS_DETAILED */
1361 afs_fsize_t newlength; /* Holds new directory length */
1362 afs_fsize_t parentLength;
1364 #if FS_STATS_DETAILED
1365 Date currDate; /*Current date */
1366 int writeIdx; /*Write index to bump */
1367 int timeIdx; /*Authorship time index to bump */
1368 #endif /* FS_STATS_DETAILED */
1370 parentptr->disk.dataVersion++;
1371 newlength = (afs_fsize_t) Length(dir);
1373 * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1374 * (create, symlink, link, makedir) so we need to check if we have enough space
1375 * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1376 * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1378 VN_GET_LEN(parentLength, parentptr);
1379 if (nBlocks(newlength) != nBlocks(parentLength)) {
1380 VAdjustDiskUsage(&errorCode, volptr,
1381 (nBlocks(newlength) - nBlocks(parentLength)),
1382 (nBlocks(newlength) - nBlocks(parentLength)));
1384 VN_SET_LEN(parentptr, newlength);
1386 #if FS_STATS_DETAILED
1388 * Update directory write stats for this volume. Note that the auth
1389 * counter is located immediately after its associated ``distance''
1392 if (a_inSameNetwork)
1393 writeIdx = VOL_STATS_SAME_NET;
1395 writeIdx = VOL_STATS_DIFF_NET;
1396 V_stat_writes(volptr, writeIdx)++;
1397 if (author != AnonymousID) {
1398 V_stat_writes(volptr, writeIdx + 1)++;
1402 * Update the volume's authorship information in response to this
1403 * directory operation. Get the current time, decide to which time
1404 * slot this operation belongs, and bump the appropriate slot.
1406 currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1408 (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1409 VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1410 VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1411 VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1412 VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : VOL_STATS_TIME_IDX_5);
1413 if (parentptr->disk.author == author) {
1414 V_stat_dirSameAuthor(volptr, timeIdx)++;
1416 V_stat_dirDiffAuthor(volptr, timeIdx)++;
1418 #endif /* FS_STATS_DETAILED */
1420 parentptr->disk.author = author;
1421 parentptr->disk.linkCount = linkcount;
1422 parentptr->disk.unixModifyTime = FT_ApproxTime(); /* This should be set from CLIENT!! */
1423 parentptr->disk.serverModifyTime = FT_ApproxTime();
1424 parentptr->changed_newTime = 1; /* vnode changed, write it back. */
1429 * Update the target file's (or dir's) status block after the specified
1430 * operation is complete. Note that some other fields maybe updated by
1431 * the individual module.
1434 /* XXX INCOMPLETE - More attention is needed here! */
1436 Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
1437 struct client *client, AFSStoreStatus * InStatus,
1438 Vnode * parentptr, Volume * volptr,
1441 #if FS_STATS_DETAILED
1442 Date currDate; /*Current date */
1443 int writeIdx; /*Write index to bump */
1444 int timeIdx; /*Authorship time index to bump */
1445 #endif /* FS_STATS_DETAILED */
1447 if (Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR)) { /* initialize new file */
1448 targetptr->disk.parent = parentptr->vnodeNumber;
1449 VN_SET_LEN(targetptr, length);
1450 /* targetptr->disk.group = 0; save some cycles */
1451 targetptr->disk.modeBits = 0777;
1452 targetptr->disk.owner = client->ViceId;
1453 targetptr->disk.dataVersion = 0; /* consistent with the client */
1454 targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1455 /* the inode was created in Alloc_NewVnode() */
1457 #if FS_STATS_DETAILED
1459 * Update file write stats for this volume. Note that the auth
1460 * counter is located immediately after its associated ``distance''
1463 if (client->InSameNetwork)
1464 writeIdx = VOL_STATS_SAME_NET;
1466 writeIdx = VOL_STATS_DIFF_NET;
1467 V_stat_writes(volptr, writeIdx)++;
1468 if (client->ViceId != AnonymousID) {
1469 V_stat_writes(volptr, writeIdx + 1)++;
1473 * We only count operations that DON'T involve creating new objects
1474 * (files, symlinks, directories) or simply setting status as
1475 * authorship-change operations.
1477 if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1479 * Update the volume's authorship information in response to this
1480 * file operation. Get the current time, decide to which time
1481 * slot this operation belongs, and bump the appropriate slot.
1483 currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1486 VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1487 VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1488 VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1489 VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1490 VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1491 VOL_STATS_TIME_IDX_5);
1492 if (targetptr->disk.author == client->ViceId) {
1493 V_stat_fileSameAuthor(volptr, timeIdx)++;
1495 V_stat_fileDiffAuthor(volptr, timeIdx)++;
1498 #endif /* FS_STATS_DETAILED */
1500 if (!(Caller & TVS_SSTATUS))
1501 targetptr->disk.author = client->ViceId;
1502 if (Caller & TVS_SDATA) {
1503 targetptr->disk.dataVersion++;
1504 if (VanillaUser(client)) {
1505 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1506 #ifdef CREATE_SGUID_ADMIN_ONLY
1507 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1511 if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1512 /* store status, must explicitly request to change the date */
1513 if (InStatus->Mask & AFS_SETMODTIME)
1514 targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1515 } else { /* other: date always changes, but perhaps to what is specified by caller */
1516 targetptr->disk.unixModifyTime =
1517 (InStatus->Mask & AFS_SETMODTIME ? InStatus->
1518 ClientModTime : FT_ApproxTime());
1520 if (InStatus->Mask & AFS_SETOWNER) {
1521 /* admin is allowed to do chmod, chown as well as chown, chmod. */
1522 if (VanillaUser(client)) {
1523 targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1524 #ifdef CREATE_SGUID_ADMIN_ONLY
1525 targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1528 targetptr->disk.owner = InStatus->Owner;
1529 if (VolumeRootVnode(targetptr)) {
1530 Error errorCode = 0; /* what should be done with this? */
1532 V_owner(targetptr->volumePtr) = InStatus->Owner;
1533 VUpdateVolume(&errorCode, targetptr->volumePtr);
1536 if (InStatus->Mask & AFS_SETMODE) {
1537 int modebits = InStatus->UnixModeBits;
1538 #define CREATE_SGUID_ADMIN_ONLY 1
1539 #ifdef CREATE_SGUID_ADMIN_ONLY
1540 if (VanillaUser(client))
1541 modebits = modebits & 0777;
1543 if (VanillaUser(client)) {
1544 targetptr->disk.modeBits = modebits;
1546 targetptr->disk.modeBits = modebits;
1549 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1550 CHK_STOREDATA, AUD_END);
1554 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1555 CHK_STORESTATUS, AUD_END);
1562 targetptr->disk.serverModifyTime = FT_ApproxTime();
1563 if (InStatus->Mask & AFS_SETGROUP)
1564 targetptr->disk.group = InStatus->Group;
1565 /* vnode changed : to be written back by VPutVnode */
1566 targetptr->changed_newTime = 1;
1568 } /*Update_TargetVnodeStatus */
1572 * Fills the CallBack structure with the expiration time and type of callback
1573 * structure. Warning: this function is currently incomplete.
1576 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1578 /* CallBackTime could not be 0 */
1579 if (CallBackTime == 0) {
1580 ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1581 CallBack->ExpirationTime = 0;
1583 CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1584 CallBack->CallBackVersion = CALLBACK_VERSION;
1585 CallBack->CallBackType = CB_SHARED; /* The default for now */
1587 } /*SetCallBackStruct */
1591 * Adjusts (Subtract) "length" number of blocks from the volume's disk
1592 * allocation; if some error occured (exceeded volume quota or partition
1593 * was full, or whatever), it frees the space back and returns the code.
1594 * We usually pre-adjust the volume space to make sure that there's
1595 * enough space before consuming some.
1598 AdjustDiskUsage(Volume * volptr, afs_sfsize_t length,
1599 afs_sfsize_t checkLength)
1604 VAdjustDiskUsage(&rc, volptr, length, checkLength);
1606 VAdjustDiskUsage(&nc, volptr, -length, 0);
1607 if (rc == VOVERQUOTA) {
1609 ("Volume %u (%s) is full\n", V_id(volptr),
1613 if (rc == VDISKFULL) {
1615 ("Partition %s that contains volume %u is full\n",
1616 volptr->partition->name, V_id(volptr)));
1619 ViceLog(0, ("Got error return %d from VAdjustDiskUsage\n", rc));
1624 } /*AdjustDiskUsage */
1627 * Common code that handles the creation of a new file (SAFS_CreateFile and
1628 * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1631 Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
1632 Vnode ** targetptr, char *Name, struct AFSFid *OutFid,
1633 int FileType, afs_sfsize_t BlocksPreallocatedForVnode)
1635 int errorCode = 0; /* Error code returned back */
1638 Inode nearInode; /* hint for inode allocation in solaris */
1641 AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1642 BlocksPreallocatedForVnode))) {
1644 ("Insufficient space to allocate %lld blocks\n",
1645 (afs_intmax_t) BlocksPreallocatedForVnode));
1649 *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1650 if (errorCode != 0) {
1651 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1654 OutFid->Volume = V_id(volptr);
1655 OutFid->Vnode = (*targetptr)->vnodeNumber;
1656 OutFid->Unique = (*targetptr)->disk.uniquifier;
1658 nearInode = VN_GET_INO(parentptr); /* parent is also in same vol */
1660 /* create the inode now itself */
1662 IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1663 VPartitionPath(V_partition(volptr)), nearInode,
1664 V_id(volptr), (*targetptr)->vnodeNumber,
1665 (*targetptr)->disk.uniquifier, 1);
1667 /* error in creating inode */
1668 if (!VALID_INO(inode)) {
1670 ("Volume : %u vnode = %u Failed to create inode: errno = %d\n",
1671 (*targetptr)->volumePtr->header->diskstuff.id,
1672 (*targetptr)->vnodeNumber, errno));
1673 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1674 (*targetptr)->delete = 1; /* delete vnode */
1677 VN_SET_INO(*targetptr, inode);
1678 IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1680 /* copy group from parent dir */
1681 (*targetptr)->disk.group = parentptr->disk.group;
1683 if (parentptr->disk.cloned) {
1684 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1685 if ((errorCode = CopyOnWrite(parentptr, volptr))) { /* disk full */
1686 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1687 /* delete the vnode previously allocated */
1688 (*targetptr)->delete = 1;
1689 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1690 IH_REALLYCLOSE((*targetptr)->handle);
1691 if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1693 ("Alloc_NewVnode: partition %s idec %s failed\n",
1694 volptr->partition->name, PrintInode(NULL, inode)));
1695 IH_RELEASE((*targetptr)->handle);
1701 /* add the name to the directory */
1702 SetDirHandle(dir, parentptr);
1703 if ((errorCode = Create(dir, (char *)Name, OutFid))) {
1704 (*targetptr)->delete = 1;
1705 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1706 IH_REALLYCLOSE((*targetptr)->handle);
1707 if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1709 ("Alloc_NewVnode: partition %s idec %s failed\n",
1710 volptr->partition->name, PrintInode(NULL, inode)));
1711 IH_RELEASE((*targetptr)->handle);
1717 } /*Alloc_NewVnode */
1721 * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1725 HandleLocking(Vnode * targetptr, struct client *client, afs_int32 rights, ViceLockType LockingType)
1727 int Time; /* Used for time */
1728 int writeVnode = targetptr->changed_oldTime; /* save original status */
1730 targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
1731 Time = FT_ApproxTime();
1732 switch (LockingType) {
1735 if (Time > targetptr->disk.lock.lockTime)
1736 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount =
1738 Time += AFS_LOCKWAIT;
1739 if (LockingType == LockRead) {
1740 if ( !(rights & PRSFS_LOCK) &&
1741 !(rights & PRSFS_WRITE) &&
1742 !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1746 if (targetptr->disk.lock.lockCount >= 0) {
1747 ++(targetptr->disk.lock.lockCount);
1748 targetptr->disk.lock.lockTime = Time;
1751 } else if (LockingType == LockWrite) {
1752 if ( !(rights & PRSFS_WRITE) &&
1753 !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1756 if (targetptr->disk.lock.lockCount == 0) {
1757 targetptr->disk.lock.lockCount = -1;
1758 targetptr->disk.lock.lockTime = Time;
1764 Time += AFS_LOCKWAIT;
1765 if (targetptr->disk.lock.lockCount != 0)
1766 targetptr->disk.lock.lockTime = Time;
1771 if ((--targetptr->disk.lock.lockCount) <= 0)
1772 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime =
1776 targetptr->changed_oldTime = writeVnode; /* restore old status */
1777 ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1780 } /*HandleLocking */
1782 /* 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. */
1785 CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
1789 if (!(rights & Prfs_Mode))
1791 if ((targetptr->disk.type != vDirectory)
1792 && (!(targetptr->disk.modeBits & OWNERWRITE)))
1798 * If some flags (i.e. min or max quota) are set, the volume's in disk
1799 * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1800 * update, if applicable.
1803 RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
1804 char *Name, char *OfflineMsg, char *Motd)
1806 Error errorCode = 0;
1808 if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1809 V_minquota(volptr) = StoreVolStatus->MinQuota;
1810 if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1811 V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1812 if (strlen(OfflineMsg) > 0) {
1813 strcpy(V_offlineMessage(volptr), OfflineMsg);
1815 if (strlen(Name) > 0) {
1816 strcpy(V_name(volptr), Name);
1818 #if OPENAFS_VOL_STATS
1820 * We don't overwrite the motd field, since it's now being used
1824 if (strlen(Motd) > 0) {
1825 strcpy(V_motd(volptr), Motd);
1827 #endif /* FS_STATS_DETAILED */
1828 VUpdateVolume(&errorCode, volptr);
1831 } /*RXUpdate_VolumeStatus */
1835 RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
1836 char **motd, Volume * volptr)
1840 status->Vid = V_id(volptr);
1841 status->ParentId = V_parentId(volptr);
1842 status->Online = V_inUse(volptr);
1843 status->InService = V_inService(volptr);
1844 status->Blessed = V_blessed(volptr);
1845 status->NeedsSalvage = V_needsSalvaged(volptr);
1846 if (VolumeWriteable(volptr))
1847 status->Type = ReadWrite;
1849 status->Type = ReadOnly;
1850 status->MinQuota = V_minquota(volptr);
1851 status->MaxQuota = V_maxquota(volptr);
1852 status->BlocksInUse = V_diskused(volptr);
1853 status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
1854 status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
1856 /* now allocate and copy these things; they're freed by the RXGEN stub */
1857 temp = strlen(V_name(volptr)) + 1;
1858 *name = malloc(temp);
1860 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1863 strcpy(*name, V_name(volptr));
1864 temp = strlen(V_offlineMessage(volptr)) + 1;
1865 *offMsg = malloc(temp);
1867 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1870 strcpy(*offMsg, V_offlineMessage(volptr));
1871 #if OPENAFS_VOL_STATS
1874 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1877 strcpy(*motd, nullString);
1879 temp = strlen(V_motd(volptr)) + 1;
1880 *motd = malloc(temp);
1882 ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1885 strcpy(*motd, V_motd(volptr));
1886 #endif /* FS_STATS_DETAILED */
1888 } /*RXGetVolumeStatus */
1892 FileNameOK(register char *aname)
1894 register afs_int32 i, tc;
1897 /* watch for @sys on the right */
1898 if (strcmp(aname + i - 4, "@sys") == 0)
1901 while ((tc = *aname++)) {
1903 return 0; /* very bad character to encounter */
1905 return 1; /* file name is ok */
1911 * This variant of symlink is expressly to support the AFS/DFS translator
1912 * and is not supported by the AFS fileserver. We just return EINVAL.
1913 * The cache manager should not generate this call to an AFS cache manager.
1916 SRXAFS_DFSSymlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
1917 char *LinkContents, struct AFSStoreStatus *InStatus,
1918 struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus,
1919 struct AFSFetchStatus *OutDirStatus,
1920 struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
1926 SRXAFS_ResidencyCmd(struct rx_call * acall, struct AFSFid * Fid,
1927 struct ResidencyCmdInputs * Inputs,
1928 struct ResidencyCmdOutputs * Outputs)
1934 static struct afs_buffer {
1935 struct afs_buffer *next;
1936 } *freeBufferList = 0;
1937 static int afs_buffersAlloced = 0;
1940 FreeSendBuffer(register struct afs_buffer *adata)
1943 afs_buffersAlloced--;
1944 adata->next = freeBufferList;
1945 freeBufferList = adata;
1949 } /*FreeSendBuffer */
1951 /* allocate space for sender */
1955 register struct afs_buffer *tp;
1958 afs_buffersAlloced++;
1959 if (!freeBufferList) {
1962 tmp = malloc(sendBufSize);
1964 ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1969 tp = freeBufferList;
1970 freeBufferList = tp->next;
1974 } /*AllocSendBuffer */
1975 #endif /* AFS_NT40_ENV */
1978 * This routine returns the status info associated with the targetptr vnode
1979 * in the AFSFetchStatus structure. Some of the newer fields, such as
1980 * SegSize and Group are not yet implemented
1984 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
1985 afs_int32 anyrights, Vnode * parentptr)
1987 /* initialize return status from a vnode */
1988 status->InterfaceVersion = 1;
1989 status->SyncCounter = status->dataVersionHigh = status->lockCount =
1990 status->errorCode = 0;
1991 status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1992 if (targetptr->disk.type == vFile)
1993 status->FileType = File;
1994 else if (targetptr->disk.type == vDirectory)
1995 status->FileType = Directory;
1996 else if (targetptr->disk.type == vSymlink)
1997 status->FileType = SymbolicLink;
1999 status->FileType = Invalid; /*invalid type field */
2000 status->LinkCount = targetptr->disk.linkCount;
2002 afs_fsize_t targetLen;
2003 VN_GET_LEN(targetLen, targetptr);
2004 SplitOffsetOrSize(targetLen, status->Length_hi, status->Length);
2006 status->DataVersion = targetptr->disk.dataVersion;
2007 status->Author = targetptr->disk.author;
2008 status->Owner = targetptr->disk.owner;
2009 status->CallerAccess = rights;
2010 status->AnonymousAccess = anyrights;
2011 status->UnixModeBits = targetptr->disk.modeBits;
2012 status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */
2013 status->ParentVnode =
2014 (status->FileType ==
2015 Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2016 status->ParentUnique =
2017 (status->FileType ==
2018 Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2019 status->ServerModTime = targetptr->disk.serverModifyTime;
2020 status->Group = targetptr->disk.group;
2021 status->lockCount = targetptr->disk.lock.lockCount;
2022 status->errorCode = 0;
2028 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
2029 afs_sfsize_t Pos, afs_sfsize_t Len,
2030 struct AFSFetchStatus *OutStatus,
2031 struct AFSCallBack *CallBack, struct AFSVolSync *Sync,
2034 Vnode *targetptr = 0; /* pointer to vnode to fetch */
2035 Vnode *parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */
2036 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2037 int errorCode = 0; /* return code to caller */
2038 int fileCode = 0; /* return code from vol package */
2039 Volume *volptr = 0; /* pointer to the volume */
2040 struct client *client = 0; /* pointer to the client data */
2041 struct rx_connection *tcon; /* the connection we're part of */
2043 afs_int32 rights, anyrights; /* rights for this and any user */
2044 struct client *t_client = NULL; /* tmp ptr to client data */
2045 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2046 #if FS_STATS_DETAILED
2047 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2048 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2049 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2050 struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2051 struct timeval elapsedTime; /* Transfer time */
2052 afs_sfsize_t bytesToXfer; /* # bytes to xfer */
2053 afs_sfsize_t bytesXferred; /* # bytes actually xferred */
2054 int readIdx; /* Index of read stats array to bump */
2055 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2058 * Set our stats pointers, remember when the RPC operation started, and
2059 * tally the operation.
2061 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2062 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2066 TM_GetTimeOfDay(&opStartTime, 0);
2067 #endif /* FS_STATS_DETAILED */
2070 ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2073 AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2075 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2078 /* Get ptr to client data for user Id for logging */
2079 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2080 logHostAddr.s_addr = rxr_HostOf(tcon);
2082 ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2083 Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2084 ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2086 * Get volume/vnode for the fetched file; caller's access rights to
2087 * it are also returned
2090 GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2091 &parentwhentargetnotdir, &client, READ_LOCK,
2092 &rights, &anyrights)))
2095 SetVolumeSync(Sync, volptr);
2097 #if FS_STATS_DETAILED
2099 * Remember that another read operation was performed.
2102 if (client->InSameNetwork)
2103 readIdx = VOL_STATS_SAME_NET;
2105 readIdx = VOL_STATS_DIFF_NET;
2106 V_stat_reads(volptr, readIdx)++;
2107 if (client->ViceId != AnonymousID) {
2108 V_stat_reads(volptr, readIdx + 1)++;
2111 #endif /* FS_STATS_DETAILED */
2112 /* Check whether the caller has permission access to fetch the data */
2114 Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
2118 * Drop the read lock on the parent directory after saving the parent
2119 * vnode information we need to pass to GetStatus
2121 if (parentwhentargetnotdir != NULL) {
2122 tparentwhentargetnotdir = *parentwhentargetnotdir;
2123 VPutVnode(&fileCode, parentwhentargetnotdir);
2124 assert(!fileCode || (fileCode == VSALVAGE));
2125 parentwhentargetnotdir = NULL;
2127 #if FS_STATS_DETAILED
2129 * Remember when the data transfer started.
2131 TM_GetTimeOfDay(&xferStartTime, 0);
2132 #endif /* FS_STATS_DETAILED */
2134 /* actually do the data transfer */
2135 #if FS_STATS_DETAILED
2137 FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2138 &bytesToXfer, &bytesXferred);
2141 FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2143 #endif /* FS_STATS_DETAILED */
2145 #if FS_STATS_DETAILED
2147 * At this point, the data transfer is done, for good or ill. Remember
2148 * when the transfer ended, bump the number of successes/failures, and
2149 * integrate the transfer size and elapsed time into the stats. If the
2150 * operation failed, we jump to the appropriate point.
2152 TM_GetTimeOfDay(&xferStopTime, 0);
2154 (xferP->numXfers)++;
2156 (xferP->numSuccesses)++;
2159 * Bump the xfer sum by the number of bytes actually sent, NOT the
2162 tot_bytesXferred += bytesXferred;
2163 (xferP->sumBytes) += (tot_bytesXferred >> 10);
2164 tot_bytesXferred &= 0x3FF;
2165 if (bytesXferred < xferP->minBytes)
2166 xferP->minBytes = bytesXferred;
2167 if (bytesXferred > xferP->maxBytes)
2168 xferP->maxBytes = bytesXferred;
2171 * Tally the size of the object. Note: we tally the actual size,
2172 * NOT the number of bytes that made it out over the wire.
2174 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2175 (xferP->count[0])++;
2176 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2177 (xferP->count[1])++;
2178 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2179 (xferP->count[2])++;
2180 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2181 (xferP->count[3])++;
2182 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2183 (xferP->count[4])++;
2184 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2185 (xferP->count[5])++;
2186 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2187 (xferP->count[6])++;
2188 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2189 (xferP->count[7])++;
2191 (xferP->count[8])++;
2193 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2194 fs_stats_AddTo((xferP->sumTime), elapsedTime);
2195 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2196 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2197 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2199 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2200 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2205 * Finally, go off to tell our caller the bad news in case the
2210 #endif /* FS_STATS_DETAILED */
2212 /* write back the OutStatus from the target vnode */
2213 GetStatus(targetptr, OutStatus, rights, anyrights,
2214 &tparentwhentargetnotdir);
2216 /* if a r/w volume, promise a callback to the caller */
2217 if (VolumeWriteable(volptr))
2218 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2220 struct AFSFid myFid;
2221 memset(&myFid, 0, sizeof(struct AFSFid));
2222 myFid.Volume = Fid->Volume;
2223 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2227 /* Update and store volume/vnode and parent vnodes back */
2228 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2230 ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2231 errorCode = CallPostamble(tcon, errorCode, thost);
2233 #if FS_STATS_DETAILED
2234 TM_GetTimeOfDay(&opStopTime, 0);
2235 if (errorCode == 0) {
2237 (opP->numSuccesses)++;
2238 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2239 fs_stats_AddTo((opP->sumTime), elapsedTime);
2240 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2241 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2242 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2244 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2245 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2249 #endif /* FS_STATS_DETAILED */
2251 osi_auditU(acall, FetchDataEvent, errorCode,
2252 AUD_ID, t_client ? t_client->ViceId : 0,
2253 AUD_FID, Fid, AUD_END);
2256 } /*SRXAFS_FetchData */
2259 SRXAFS_FetchData(struct rx_call * acall, struct AFSFid * Fid, afs_int32 Pos,
2260 afs_int32 Len, struct AFSFetchStatus * OutStatus,
2261 struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2263 return common_FetchData64(acall, Fid, Pos, Len, OutStatus, CallBack,
2268 SRXAFS_FetchData64(struct rx_call * acall, struct AFSFid * Fid, afs_int64 Pos,
2269 afs_int64 Len, struct AFSFetchStatus * OutStatus,
2270 struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2273 afs_sfsize_t tPos, tLen;
2275 #ifdef AFS_64BIT_ENV
2276 #ifndef AFS_LARGEFILE_ENV
2277 if (Pos + Len > 0x7fffffff)
2279 #endif /* !AFS_LARGEFILE_ENV */
2280 tPos = (afs_sfsize_t) Pos;
2281 tLen = (afs_sfsize_t) Len;
2282 #else /* AFS_64BIT_ENV */
2283 if (Pos.high || Len.high)
2287 #endif /* AFS_64BIT_ENV */
2290 common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2296 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2297 struct AFSOpaque * AccessList,
2298 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2300 Vnode *targetptr = 0; /* pointer to vnode to fetch */
2301 Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2302 int errorCode = 0; /* return error code to caller */
2303 Volume *volptr = 0; /* pointer to the volume */
2304 struct client *client = 0; /* pointer to the client data */
2305 afs_int32 rights, anyrights; /* rights for this and any user */
2306 struct rx_connection *tcon = rx_ConnectionOf(acall);
2308 struct client *t_client = NULL; /* tmp ptr to client data */
2309 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2310 #if FS_STATS_DETAILED
2311 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2312 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2313 struct timeval elapsedTime; /* Transfer time */
2316 * Set our stats pointer, remember when the RPC operation started, and
2317 * tally the operation.
2319 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2323 TM_GetTimeOfDay(&opStartTime, 0);
2324 #endif /* FS_STATS_DETAILED */
2327 ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2330 AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2332 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2335 /* Get ptr to client data for user Id for logging */
2336 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2337 logHostAddr.s_addr = rxr_HostOf(tcon);
2339 ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2340 Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2341 ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2343 AccessList->AFSOpaque_len = 0;
2344 AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2345 if (!AccessList->AFSOpaque_val) {
2346 ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2351 * Get volume/vnode for the fetched file; caller's access rights to it
2355 GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2356 &parentwhentargetnotdir, &client, READ_LOCK,
2357 &rights, &anyrights)))
2360 SetVolumeSync(Sync, volptr);
2362 /* Check whether we have permission to fetch the ACL */
2364 Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2367 /* Get the Access List from the dir's vnode */
2369 RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2372 /* Get OutStatus back From the target Vnode */
2373 GetStatus(targetptr, OutStatus, rights, anyrights,
2374 parentwhentargetnotdir);
2377 /* Update and store volume/vnode and parent vnodes back */
2378 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2381 ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2382 AccessList->AFSOpaque_val));
2383 errorCode = CallPostamble(tcon, errorCode, thost);
2385 #if FS_STATS_DETAILED
2386 TM_GetTimeOfDay(&opStopTime, 0);
2387 if (errorCode == 0) {
2389 (opP->numSuccesses)++;
2390 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2391 fs_stats_AddTo((opP->sumTime), elapsedTime);
2392 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2393 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2394 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2396 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2397 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2401 #endif /* FS_STATS_DETAILED */
2403 osi_auditU(acall, FetchACLEvent, errorCode,
2404 AUD_ID, t_client ? t_client->ViceId : 0,
2406 AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2408 } /*SRXAFS_FetchACL */
2412 * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2413 * merged into it when possible.
2417 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2418 struct AFSFetchStatus *OutStatus,
2419 struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2421 Vnode *targetptr = 0; /* pointer to vnode to fetch */
2422 Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2423 int errorCode = 0; /* return code to caller */
2424 Volume *volptr = 0; /* pointer to the volume */
2425 struct client *client = 0; /* pointer to the client data */
2426 afs_int32 rights, anyrights; /* rights for this and any user */
2427 struct client *t_client = NULL; /* tmp ptr to client data */
2428 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2429 struct rx_connection *tcon = rx_ConnectionOf(acall);
2431 /* Get ptr to client data for user Id for logging */
2432 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2433 logHostAddr.s_addr = rxr_HostOf(tcon);
2435 ("SAFS_FetchStatus, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2436 Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2437 ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2439 AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2442 * Get volume/vnode for the fetched file; caller's rights to it are
2446 GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2447 &parentwhentargetnotdir, &client, READ_LOCK,
2448 &rights, &anyrights)))
2449 goto Bad_FetchStatus;
2451 /* set volume synchronization information */
2452 SetVolumeSync(Sync, volptr);
2454 /* Are we allowed to fetch Fid's status? */
2455 if (targetptr->disk.type != vDirectory) {
2457 Check_PermissionRights(targetptr, client, rights,
2458 CHK_FETCHSTATUS, 0))) {
2459 if (rx_GetCallAbortCode(acall) == errorCode)
2460 rx_SetCallAbortCode(acall, 0);
2461 goto Bad_FetchStatus;
2465 /* set OutStatus From the Fid */
2466 GetStatus(targetptr, OutStatus, rights, anyrights,
2467 parentwhentargetnotdir);
2469 /* If a r/w volume, also set the CallBack state */
2470 if (VolumeWriteable(volptr))
2471 SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2473 struct AFSFid myFid;
2474 memset(&myFid, 0, sizeof(struct AFSFid));
2475 myFid.Volume = Fid->Volume;
2476 SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2480 /* Update and store volume/vnode and parent vnodes back */
2481 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2483 ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2486 } /*SAFSS_FetchStatus */
2490 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2491 struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2492 struct AFSVolSync * Sync)
2496 Vnode *targetptr = 0; /* pointer to vnode to fetch */
2497 Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2498 int errorCode = 0; /* return code to caller */
2499 Volume *volptr = 0; /* pointer to the volume */
2500 struct client *client = 0; /* pointer to the client data */
2501 afs_int32 rights, anyrights; /* rights for this and any user */
2502 register struct AFSFid *tfid; /* file id we're dealing with now */
2503 struct rx_connection *tcon = rx_ConnectionOf(acall);
2505 struct client *t_client = NULL; /* tmp pointer to the client data */
2506 #if FS_STATS_DETAILED
2507 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2508 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2509 struct timeval elapsedTime; /* Transfer time */
2512 * Set our stats pointer, remember when the RPC operation started, and
2513 * tally the operation.
2515 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2519 TM_GetTimeOfDay(&opStartTime, 0);
2520 #endif /* FS_STATS_DETAILED */
2522 ViceLog(1, ("SAFS_BulkStatus\n"));
2524 AFSCallStats.TotalCalls++;
2526 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2527 if (nfiles <= 0) { /* Sanity check */
2529 goto Audit_and_Return;
2532 /* allocate space for return output parameters */
2533 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2534 malloc(nfiles * sizeof(struct AFSFetchStatus));
2535 if (!OutStats->AFSBulkStats_val) {
2536 ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2539 OutStats->AFSBulkStats_len = nfiles;
2540 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2541 malloc(nfiles * sizeof(struct AFSCallBack));
2542 if (!CallBacks->AFSCBs_val) {
2543 ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2546 CallBacks->AFSCBs_len = nfiles;
2548 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2549 goto Bad_BulkStatus;
2551 tfid = Fids->AFSCBFids_val;
2552 for (i = 0; i < nfiles; i++, tfid++) {
2554 * Get volume/vnode for the fetched file; caller's rights to it
2558 GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2559 &parentwhentargetnotdir, &client, READ_LOCK,
2560 &rights, &anyrights)))
2561 goto Bad_BulkStatus;
2562 /* set volume synchronization information, but only once per call */
2564 SetVolumeSync(Sync, volptr);
2566 /* Are we allowed to fetch Fid's status? */
2567 if (targetptr->disk.type != vDirectory) {
2569 Check_PermissionRights(targetptr, client, rights,
2570 CHK_FETCHSTATUS, 0))) {
2571 if (rx_GetCallAbortCode(acall) == errorCode)
2572 rx_SetCallAbortCode(acall, 0);
2573 goto Bad_BulkStatus;
2577 /* set OutStatus From the Fid */
2578 GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2579 anyrights, parentwhentargetnotdir);
2581 /* If a r/w volume, also set the CallBack state */
2582 if (VolumeWriteable(volptr))
2583 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2584 &CallBacks->AFSCBs_val[i]);
2586 struct AFSFid myFid;
2587 memset(&myFid, 0, sizeof(struct AFSFid));
2588 myFid.Volume = tfid->Volume;
2589 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2590 &CallBacks->AFSCBs_val[i]);
2593 /* put back the file ID and volume */
2594 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2596 parentwhentargetnotdir = (Vnode *) 0;
2597 targetptr = (Vnode *) 0;
2598 volptr = (Volume *) 0;
2599 client = (struct client *)0;
2603 /* Update and store volume/vnode and parent vnodes back */
2604 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2606 errorCode = CallPostamble(tcon, errorCode, thost);
2608 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2610 #if FS_STATS_DETAILED
2611 TM_GetTimeOfDay(&opStopTime, 0);
2612 if (errorCode == 0) {
2614 (opP->numSuccesses)++;
2615 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2616 fs_stats_AddTo((opP->sumTime), elapsedTime);
2617 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2618 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2619 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2621 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2622 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2626 #endif /* FS_STATS_DETAILED */
2629 ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode));
2630 osi_auditU(acall, BulkFetchStatusEvent, errorCode,
2631 AUD_ID, t_client ? t_client->ViceId : 0,
2632 AUD_FIDS, Fids, AUD_END);
2635 } /*SRXAFS_BulkStatus */
2639 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2640 struct AFSBulkStats * OutStats,
2641 struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2645 Vnode *targetptr = 0; /* pointer to vnode to fetch */
2646 Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2647 int errorCode = 0; /* return code to caller */
2648 Volume *volptr = 0; /* pointer to the volume */
2649 struct client *client = 0; /* pointer to the client data */
2650 afs_int32 rights, anyrights; /* rights for this and any user */
2651 register struct AFSFid *tfid; /* file id we're dealing with now */
2652 struct rx_connection *tcon;
2654 struct client *t_client = NULL; /* tmp ptr to client data */
2655 AFSFetchStatus *tstatus;
2656 #if FS_STATS_DETAILED
2657 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2658 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2659 struct timeval elapsedTime; /* Transfer time */
2662 * Set our stats pointer, remember when the RPC operation started, and
2663 * tally the operation.
2665 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2669 TM_GetTimeOfDay(&opStartTime, 0);
2670 #endif /* FS_STATS_DETAILED */
2672 ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2674 AFSCallStats.TotalCalls++;
2676 nfiles = Fids->AFSCBFids_len; /* # of files in here */
2677 if (nfiles <= 0) { /* Sanity check */
2679 goto Audit_and_Return;
2682 /* allocate space for return output parameters */
2683 OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2684 malloc(nfiles * sizeof(struct AFSFetchStatus));
2685 if (!OutStats->AFSBulkStats_val) {
2686 ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2689 OutStats->AFSBulkStats_len = nfiles;
2690 CallBacks->AFSCBs_val = (struct AFSCallBack *)
2691 malloc(nfiles * sizeof(struct AFSCallBack));
2692 if (!CallBacks->AFSCBs_val) {
2693 ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2696 CallBacks->AFSCBs_len = nfiles;
2698 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2699 goto Bad_InlineBulkStatus;
2702 tfid = Fids->AFSCBFids_val;
2703 for (i = 0; i < nfiles; i++, tfid++) {
2705 * Get volume/vnode for the fetched file; caller's rights to it
2709 GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2710 &parentwhentargetnotdir, &client, READ_LOCK,
2711 &rights, &anyrights))) {
2712 tstatus = &OutStats->AFSBulkStats_val[i];
2713 tstatus->errorCode = errorCode;
2714 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2716 parentwhentargetnotdir = (Vnode *) 0;
2717 targetptr = (Vnode *) 0;
2718 volptr = (Volume *) 0;
2719 client = (struct client *)0;
2723 /* set volume synchronization information, but only once per call */
2725 SetVolumeSync(Sync, volptr);
2727 /* Are we allowed to fetch Fid's status? */
2728 if (targetptr->disk.type != vDirectory) {
2730 Check_PermissionRights(targetptr, client, rights,
2731 CHK_FETCHSTATUS, 0))) {
2732 tstatus = &OutStats->AFSBulkStats_val[i];
2733 tstatus->errorCode = errorCode;
2734 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2735 (Vnode *) 0, volptr, &client);
2736 parentwhentargetnotdir = (Vnode *) 0;
2737 targetptr = (Vnode *) 0;
2738 volptr = (Volume *) 0;
2739 client = (struct client *)0;
2744 /* set OutStatus From the Fid */
2745 GetStatus(targetptr,
2746 (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2747 rights, anyrights, parentwhentargetnotdir);
2749 /* If a r/w volume, also set the CallBack state */
2750 if (VolumeWriteable(volptr))
2751 SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2752 &CallBacks->AFSCBs_val[i]);
2754 struct AFSFid myFid;
2755 memset(&myFid, 0, sizeof(struct AFSFid));
2756 myFid.Volume = tfid->Volume;
2757 SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2758 &CallBacks->AFSCBs_val[i]);
2761 /* put back the file ID and volume */
2762 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2764 parentwhentargetnotdir = (Vnode *) 0;
2765 targetptr = (Vnode *) 0;
2766 volptr = (Volume *) 0;
2767 client = (struct client *)0;
2770 Bad_InlineBulkStatus:
2771 /* Update and store volume/vnode and parent vnodes back */
2772 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2774 errorCode = CallPostamble(tcon, errorCode, thost);
2776 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2778 #if FS_STATS_DETAILED
2779 TM_GetTimeOfDay(&opStopTime, 0);
2780 if (errorCode == 0) {
2782 (opP->numSuccesses)++;
2783 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2784 fs_stats_AddTo((opP->sumTime), elapsedTime);
2785 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2786 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2787 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2789 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2790 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2794 #endif /* FS_STATS_DETAILED */
2797 ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode));
2798 osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode,
2799 AUD_ID, t_client ? t_client->ViceId : 0,
2800 AUD_FIDS, Fids, AUD_END);
2803 } /*SRXAFS_InlineBulkStatus */
2807 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2808 struct AFSFetchStatus * OutStatus,
2809 struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2812 struct rx_connection *tcon;
2814 struct client *t_client = NULL; /* tmp ptr to client data */
2815 #if FS_STATS_DETAILED
2816 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2817 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2818 struct timeval elapsedTime; /* Transfer time */
2821 * Set our stats pointer, remember when the RPC operation started, and
2822 * tally the operation.
2824 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2828 TM_GetTimeOfDay(&opStartTime, 0);
2829 #endif /* FS_STATS_DETAILED */
2831 if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2832 goto Bad_FetchStatus;
2834 code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
2837 code = CallPostamble(tcon, code, thost);
2839 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2841 #if FS_STATS_DETAILED
2842 TM_GetTimeOfDay(&opStopTime, 0);
2845 (opP->numSuccesses)++;
2846 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2847 fs_stats_AddTo((opP->sumTime), elapsedTime);
2848 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2849 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2850 fs_stats_TimeAssign((opP->minTime), elapsedTime);
2852 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2853 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2857 #endif /* FS_STATS_DETAILED */
2859 osi_auditU(acall, FetchStatusEvent, code,
2860 AUD_ID, t_client ? t_client->ViceId : 0,
2861 AUD_FID, Fid, AUD_END);
2864 } /*SRXAFS_FetchStatus */
2868 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
2869 struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
2870 afs_fsize_t Length, afs_fsize_t FileLength,
2871 struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
2873 Vnode *targetptr = 0; /* pointer to input fid */
2874 Vnode *parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2875 Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */
2876 int errorCode = 0; /* return code for caller */
2877 int fileCode = 0; /* return code from vol package */
2878 Volume *volptr = 0; /* pointer to the volume header */
2879 struct client *client = 0; /* pointer to client structure */
2880 afs_int32 rights, anyrights; /* rights for this and any user */
2881 struct client *t_client = NULL; /* tmp ptr to client data */
2882 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2883 struct rx_connection *tcon;
2885 #if FS_STATS_DETAILED
2886 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
2887 struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
2888 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
2889 struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2890 struct timeval elapsedTime; /* Transfer time */
2891 afs_sfsize_t bytesToXfer; /* # bytes to xfer */
2892 afs_sfsize_t bytesXferred; /* # bytes actually xfer */
2893 static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2896 * Set our stats pointers, remember when the RPC operation started, and
2897 * tally the operation.
2899 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2900 xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2905 ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2907 TM_GetTimeOfDay(&opStartTime, 0);
2908 #endif /* FS_STATS_DETAILED */
2911 AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2913 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2916 /* Get ptr to client data for user Id for logging */
2917 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2918 logHostAddr.s_addr = rxr_HostOf(tcon);
2920 ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2921 Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2922 ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2925 * Get associated volume/vnode for the stored file; caller's rights
2929 GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
2930 &parentwhentargetnotdir, &client, WRITE_LOCK,
2931 &rights, &anyrights))) {
2935 /* set volume synchronization information */
2936 SetVolumeSync(Sync, volptr);
2938 if ((targetptr->disk.type == vSymlink)) {
2939 /* Should we return a better error code here??? */
2944 /* Check if we're allowed to store the data */
2946 Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
2952 * Drop the read lock on the parent directory after saving the parent
2953 * vnode information we need to pass to GetStatus
2955 if (parentwhentargetnotdir != NULL) {
2956 tparentwhentargetnotdir = *parentwhentargetnotdir;
2957 VPutVnode(&fileCode, parentwhentargetnotdir);
2958 assert(!fileCode || (fileCode == VSALVAGE));
2959 parentwhentargetnotdir = NULL;
2961 #if FS_STATS_DETAILED
2963 * Remember when the data transfer started.
2965 TM_GetTimeOfDay(&xferStartTime, 0);
2966 #endif /* FS_STATS_DETAILED */
2968 /* Do the actual storing of the data */
2969 #if FS_STATS_DETAILED
2971 StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2972 FileLength, (InStatus->Mask & AFS_FSYNC),
2973 &bytesToXfer, &bytesXferred);
2976 StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2977 FileLength, (InStatus->Mask & AFS_FSYNC));
2978 if (errorCode && (!targetptr->changed_newTime))
2980 #endif /* FS_STATS_DETAILED */
2981 #if FS_STATS_DETAILED
2983 * At this point, the data transfer is done, for good or ill. Remember
2984 * when the transfer ended, bump the number of successes/failures, and
2985 * integrate the transfer size and elapsed time into the stats. If the
2986 * operation failed, we jump to the appropriate point.
2988 TM_GetTimeOfDay(&xferStopTime, 0);
2990 (xferP->numXfers)++;
2992 (xferP->numSuccesses)++;
2995 * Bump the xfer sum by the number of bytes actually sent, NOT the
2998 tot_bytesXferred += bytesXferred;
2999 (xferP->sumBytes) += (tot_bytesXferred >> 10);
3000 tot_bytesXferred &= 0x3FF;
3001 if (bytesXferred < xferP->minBytes)
3002 xferP->minBytes = bytesXferred;
3003 if (bytesXferred > xferP->maxBytes)
3004 xferP->maxBytes = bytesXferred;
3007 * Tally the size of the object. Note: we tally the actual size,
3008 * NOT the number of bytes that made it out over the wire.
3010 if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3011 (xferP->count[0])++;
3012 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3013 (xferP->count[1])++;
3014 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3015 (xferP->count[2])++;
3016 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3017 (xferP->count[3])++;
3018 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3019 (xferP->count[4])++;
3020 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3021 (xferP->count[5])++;
3022 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3023 (xferP->count[6])++;
3024 else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3025 (xferP->count[7])++;
3027 (xferP->count[8])++;
3029 fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3030 fs_stats_AddTo((xferP->sumTime), elapsedTime);
3031 fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3032 if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3033 fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3035 if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3036 fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3041 * Finally, go off to tell our caller the bad news in case the
3044 if (errorCode && (!targetptr->changed_newTime))
3046 #endif /* FS_STATS_DETAILED */
3048 /* Update the status of the target's vnode */
3049 Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3050 targetptr, volptr, 0);
3052 /* Get the updated File's status back to the caller */
3053 GetStatus(targetptr, OutStatus, rights, anyrights,
3054 &tparentwhentargetnotdir);
3057 /* Update and store volume/vnode and parent vnodes back */
3058 (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3060 ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3062 errorCode = CallPostamble(tcon, errorCode, thost);
3064 #if FS_STATS_DETAILED
3065 TM_GetTimeOfDay(&opStopTime, 0);
3066 if (errorCode == 0) {
3068 (opP->numSuccesses)++;
3069 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3070 fs_stats_AddTo((opP->sumTime), elapsedTime);
3071 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3072 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3073 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3075 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3076 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3080 #endif /* FS_STATS_DETAILED */
3081 osi_auditU(acall, StoreDataEvent, errorCode,
3082 AUD_ID, t_client ? t_client->ViceId : 0,
3083 AUD_FID, Fid, AUD_END);
3085 } /*common_StoreData64 */
3088 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3089 struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3090 afs_uint32 Length, afs_uint32 FileLength,
3091 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3093 if (FileLength > 0x7fffffff || Pos > 0x7fffffff ||
3094 (0x7fffffff - Pos) < Length)
3097 return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3099 } /*SRXAFS_StoreData */
3102 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3103 struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3104 afs_uint64 Length, afs_uint64 FileLength,
3105 struct AFSFetchStatus * OutStatus,
3106 struct AFSVolSync * Sync)
3110 afs_fsize_t tLength;
3111 afs_fsize_t tFileLength;
3113 #ifdef AFS_64BIT_ENV
3114 #ifndef AFS_LARGEFILE_ENV
3115 if (FileLength > 0x7fffffff)
3117 #endif /* !AFS_LARGEFILE_ENV */
3118 tPos = (afs_fsize_t) Pos;
3119 tLength = (afs_fsize_t) Length;
3120 tFileLength = (afs_fsize_t) FileLength;
3121 #else /* AFS_64BIT_ENV */
3122 if (FileLength.high)
3125 tLength = Length.low;
3126 tFileLength = FileLength.low;
3127 #endif /* AFS_64BIT_ENV */
3130 common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3136 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3137 struct AFSOpaque * AccessList,
3138 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3140 Vnode *targetptr = 0; /* pointer to input fid */
3141 Vnode *parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3142 int errorCode = 0; /* return code for caller */
3143 struct AFSStoreStatus InStatus; /* Input status for fid */
3144 Volume *volptr = 0; /* pointer to the volume header */
3145 struct client *client = 0; /* pointer to client structure */
3146 afs_int32 rights, anyrights; /* rights for this and any user */
3147 struct rx_connection *tcon;
3149 struct client *t_client = NULL; /* tmp ptr to client data */
3150 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3151 #if FS_STATS_DETAILED
3152 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3153 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
3154 struct timeval elapsedTime; /* Transfer time */
3157 * Set our stats pointer, remember when the RPC operation started, and
3158 * tally the operation.
3160 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3164 TM_GetTimeOfDay(&opStartTime, 0);
3165 #endif /* FS_STATS_DETAILED */
3166 if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3169 /* Get ptr to client data for user Id for logging */
3170 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3171 logHostAddr.s_addr = rxr_HostOf(tcon);
3173 ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3174 Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3175 inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3177 AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3179 InStatus.Mask = 0; /* not storing any status */
3182 * Get associated volume/vnode for the target dir; caller's rights
3183 * are also returned.
3186 GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3187 &parentwhentargetnotdir, &client, WRITE_LOCK,
3188 &rights, &anyrights))) {
3192 /* set volume synchronization information */
3193 SetVolumeSync(Sync, volptr);
3195 /* Check if we have permission to change the dir's ACL */
3197 Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3202 /* Build and store the new Access List for the dir */
3203 if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3207 targetptr->changed_newTime = 1; /* status change of directory */
3209 /* convert the write lock to a read lock before breaking callbacks */
3210 VVnodeWriteToRead(&errorCode, targetptr);
3211 assert(!errorCode || errorCode == VSALVAGE);
3213 /* break call backs on the directory */
3214 BreakCallBack(client->host, Fid, 0);
3216 /* Get the updated dir's status back to the caller */
3217 GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3220 /* Update and store volume/vnode and parent vnodes back */
3221 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3223 ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3224 errorCode = CallPostamble(tcon, errorCode, thost);
3226 #if FS_STATS_DETAILED
3227 TM_GetTimeOfDay(&opStopTime, 0);
3228 if (errorCode == 0) {
3230 (opP->numSuccesses)++;
3231 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3232 fs_stats_AddTo((opP->sumTime), elapsedTime);
3233 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3234 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3235 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3237 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3238 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3242 #endif /* FS_STATS_DETAILED */
3244 osi_auditU(acall, StoreACLEvent, errorCode,
3245 AUD_ID, t_client ? t_client->ViceId : 0,
3246 AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3249 } /*SRXAFS_StoreACL */
3253 * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3254 * should be merged when possible.
3257 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3258 struct AFSStoreStatus *InStatus,
3259 struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3261 Vnode *targetptr = 0; /* pointer to input fid */
3262 Vnode *parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3263 int errorCode = 0; /* return code for caller */
3264 Volume *volptr = 0; /* pointer to the volume header */
3265 struct client *client = 0; /* pointer to client structure */
3266 afs_int32 rights, anyrights; /* rights for this and any user */
3267 struct client *t_client = NULL; /* tmp ptr to client data */
3268 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3269 struct rx_connection *tcon = rx_ConnectionOf(acall);
3271 /* Get ptr to client data for user Id for logging */
3272 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3273 logHostAddr.s_addr = rxr_HostOf(tcon);
3275 ("SAFS_StoreStatus, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
3276 Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3277 ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3279 AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3282 * Get volume/vnode for the target file; caller's rights to it are
3286 GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3287 &parentwhentargetnotdir, &client, WRITE_LOCK,
3288 &rights, &anyrights))) {
3289 goto Bad_StoreStatus;
3292 /* set volume synchronization information */
3293 SetVolumeSync(Sync, volptr);
3295 /* Check if the caller has proper permissions to store status to Fid */
3297 Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3299 goto Bad_StoreStatus;
3302 * Check for a symbolic link; we can't chmod these (otherwise could
3303 * change a symlink to a mt pt or vice versa)
3305 if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3307 goto Bad_StoreStatus;
3310 /* Update the status of the target's vnode */
3311 Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3312 (parentwhentargetnotdir ? parentwhentargetnotdir
3313 : targetptr), volptr, 0);
3315 /* convert the write lock to a read lock before breaking callbacks */
3316 VVnodeWriteToRead(&errorCode, targetptr);
3317 assert(!errorCode || errorCode == VSALVAGE);
3319 /* Break call backs on Fid */
3320 BreakCallBack(client->host, Fid, 0);
3322 /* Return the updated status back to caller */
3323 GetStatus(targetptr, OutStatus, rights, anyrights,
3324 parentwhentargetnotdir);
3327 /* Update and store volume/vnode and parent vnodes back */
3328 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3330 ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3333 } /*SAFSS_StoreStatus */
3337 SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
3338 struct AFSStoreStatus * InStatus,
3339 struct AFSFetchStatus * OutStatus,
3340 struct AFSVolSync * Sync)
3343 struct rx_connection *tcon;
3345 struct client *t_client = NULL; /* tmp ptr to client data */
3346 #if FS_STATS_DETAILED
3347 struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
3348 struct timeval opStartTime, opStopTime; /* Start/stop times for RPC op */
3349 struct timeval elapsedTime; /* Transfer time */
3352 * Set our stats pointer, remember when the RPC operation started, and
3353 * tally the operation.
3355 opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3359 TM_GetTimeOfDay(&opStartTime, 0);
3360 #endif /* FS_STATS_DETAILED */
3362 if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3363 goto Bad_StoreStatus;
3365 code = SAFSS_StoreStatus(acall, Fid, InStatus, OutStatus, Sync);
3368 code = CallPostamble(tcon, code, thost);
3370 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3372 #if FS_STATS_DETAILED
3373 TM_GetTimeOfDay(&opStopTime, 0);
3376 (opP->numSuccesses)++;
3377 fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3378 fs_stats_AddTo((opP->sumTime), elapsedTime);
3379 fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3380 if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3381 fs_stats_TimeAssign((opP->minTime), elapsedTime);
3383 if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3384 fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3388 #endif /* FS_STATS_DETAILED */
3390 osi_auditU(acall, StoreStatusEvent, code,
3391 AUD_ID, t_client ? t_client->ViceId : 0,
3392 AUD_FID, Fid, AUD_END);
3395 } /*SRXAFS_StoreStatus */
3399 * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3400 * merged in when possible.
3403 SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
3404 struct AFSFetchStatus *OutDirStatus, struct AFSVolSync *Sync)
3406 Vnode *parentptr = 0; /* vnode of input Directory */
3407 Vnode *parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3408 Vnode *targetptr = 0; /* file to be deleted */
3409 Volume *volptr = 0; /* pointer to the volume header */
3410 AFSFid fileFid; /* area for Fid from the directory */
3411 int errorCode = 0; /* error code */
3412 DirHandle dir; /* Handle for dir package I/O */
3413 struct client *client = 0; /* pointer to client structure */
3414 afs_int32 rights, anyrights; /* rights for this and any user */
3415 struct client *t_client; /* tmp ptr to client data */
3416 struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3417 struct rx_connection *tcon = rx_ConnectionOf(acall);
3420 /* Get ptr to client data for user Id for logging */
3421 t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3422 logHostAddr.s_addr = rxr_HostOf(tcon);
3424 ("SAFS_RemoveFile %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name,
3425 DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3426 inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3428 AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3431 * Get volume/vnode for the parent dir; caller's access rights are
3435 GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
3436 &parentwhentargetnotdir, &client, WRITE_LOCK,
3437 &rights, &anyrights))) {
3438 goto Bad_RemoveFile;
3440 /* set volume synchronization information */
3441 SetVolumeSync(Sync, volptr);
3443 /* Does the caller has delete (& write) access to the parent directory? */
3444 if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3445 goto Bad_RemoveFile;
3448 /* Actually delete the desired file */
3450 DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid, Name,
3452 goto Bad_RemoveFile;
3455 /* Update the vnode status of the parent dir */
3456 #if FS_STATS_DETAILED
3457 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3458 parentptr->disk.linkCount,
3459 client->InSameNetwork);
3461 Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3462 parentptr->disk.linkCount);
3463 #endif /* FS_STATS_DETAILED */
3465 /* Return the updated parent di