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 * GetVolumePackage disables Rx keepalives; PutVolumePackage re-enables.
24 * If callbacks are to be broken, keepalives should be enabled in the
25 * stub while that occurs; disabled while disk I/O is in process.
29 * in Check_PermissionRights, certain privileges are afforded to the owner
30 * of the volume, or the owner of a file. Are these considered "use of
34 #include <afsconfig.h>
35 #include <afs/param.h>
41 #undef SHARED /* XXX */
48 #ifdef HAVE_NETINET_IF_ETHER_H
49 #include <netinet/if_ether.h>
52 #if !defined(AFS_SGI_ENV) && defined(HAVE_SYS_MAP_H)
56 #ifdef HAVE_SYS_STATFS_H
57 #include <sys/statfs.h>
60 #ifdef HAVE_SYS_LOCKF_H
61 #include <sys/lockf.h>
69 /* included early because of name conflict on IOPEN */
70 #include <sys/inode.h>
74 #endif /* AFS_HPUX_ENV */
77 #include <rx/rx_queue.h>
81 #include <afs/afsint.h>
82 #include <afs/vldbint.h>
83 #include <afs/errors.h>
84 #include <afs/ihandle.h>
85 #include <afs/vnode.h>
86 #include <afs/volume.h>
87 #include <afs/ptclient.h>
88 #include <afs/ptuser.h>
89 #include <afs/prs_fs.h>
92 #include <rx/rx_globals.h>
94 #include <afs/cellconfig.h>
97 #include <afs/partition.h>
98 #include "viced_prototypes.h"
101 #include "callback.h"
102 #include <afs/unified_afs.h>
103 #include <afs/audit.h>
104 #include <afs/afsutil.h>
107 extern void SetDirHandle(DirHandle
* dir
, Vnode
* vnode
);
108 extern void FidZap(DirHandle
* file
);
109 extern void FidZero(DirHandle
* file
);
111 pthread_mutex_t fileproc_glock_mutex
;
113 /* Useful local defines used by this module */
116 #define MustNOTBeDIR 1
120 #define TVS_SSTATUS 2
123 #define TVS_MKDIR 0x10
125 #define CHK_FETCH 0x10
126 #define CHK_FETCHDATA 0x10
127 #define CHK_FETCHACL 0x11
128 #define CHK_FETCHSTATUS 0x12
129 #define CHK_STOREDATA 0x00
130 #define CHK_STOREACL 0x01
131 #define CHK_STORESTATUS 0x02
133 #define OWNERREAD 0400
134 #define OWNERWRITE 0200
135 #define OWNEREXEC 0100
136 #ifdef USE_GROUP_PERMS
137 #define GROUPREAD 0040
138 #define GROUPWRITE 0020
139 #define GROUPREXEC 0010
142 /* The following errors were not defined in NT. They are given unique
143 * names here to avoid any potential collision.
145 #define FSERR_ELOOP 90
146 #define FSERR_EOPNOTSUPP 122
147 #define FSERR_ECONNREFUSED 130
149 #define NOTACTIVECALL 0
152 #define CREATE_SGUID_ADMIN_ONLY 1
156 * Abort the fileserver on fatal errors returned from vnode operations.
158 #define assert_vnode_success_or_salvaging(code) \
159 opr_Assert((code) == 0 || (code) == VSALVAGE || (code) == VSALVAGING)
161 extern struct afsconf_dir
*confDir
;
162 extern afs_int32 dataVersionHigh
;
165 static struct AFSCallStatistics AFSCallStats
;
166 struct fs_stats_FullPerfStats afs_FullPerfStats
;
167 extern int AnonymousID
;
168 static const char nullString
[] = "";
171 afs_int32 NothingYet
;
174 struct afs_FSStats afs_fsstats
;
178 afs_int32 BlocksSpare
= 1024; /* allow 1 MB overruns */
180 extern afs_int32 implicitAdminRights
;
181 extern afs_int32 readonlyServer
;
182 extern int CopyOnWrite_calls
, CopyOnWrite_off0
, CopyOnWrite_size0
;
183 extern afs_fsize_t CopyOnWrite_maxsize
;
186 * Externals used by the xstat code.
188 extern VolPkgStats VStats
;
189 extern int CEs
, CEBlocks
;
191 extern int HTs
, HTBlocks
;
193 static afs_int32
FetchData_RXStyle(Volume
* volptr
, Vnode
* targetptr
,
194 struct rx_call
*Call
, afs_sfsize_t Pos
,
195 afs_sfsize_t Len
, afs_int32 Int64Mode
,
196 afs_sfsize_t
* a_bytesToFetchP
,
197 afs_sfsize_t
* a_bytesFetchedP
);
199 static afs_int32
StoreData_RXStyle(Volume
* volptr
, Vnode
* targetptr
,
200 struct AFSFid
*Fid
, struct client
*client
,
201 struct rx_call
*Call
, afs_fsize_t Pos
,
202 afs_fsize_t Length
, afs_fsize_t FileLength
,
204 afs_sfsize_t
* a_bytesToStoreP
,
205 afs_sfsize_t
* a_bytesStoredP
);
207 #ifdef AFS_SGI_XFS_IOPS_ENV
208 #include <afs/xfsattrs.h>
210 GetLinkCount(Volume
* avp
, struct stat
*astat
)
212 if (!strcmp("xfs", astat
->st_fstype
)) {
213 return (astat
->st_mode
& AFS_XFS_MODE_LINK_MASK
);
215 return astat
->st_nlink
;
218 #define GetLinkCount(V, S) (S)->st_nlink
222 SpareComp(Volume
* avolp
)
228 temp
= V_maxquota(avolp
);
230 /* no matter; doesn't check in this case */
234 temp
= (temp
* PctSpare
) / 100;
245 * Set the volume synchronization parameter for this volume. If it changes,
246 * the Cache Manager knows that the volume must be purged from the stat cache.
249 SetVolumeSync(struct AFSVolSync
*async
, Volume
* avol
)
252 /* date volume instance was created */
255 async
->spare1
= V_creationDate(avol
);
268 * Verify that the on-disk size for a vnode matches the length in the vnode
271 * @param[in] vp Volume pointer
272 * @param[in] vnp Vnode pointer
273 * @param[in] alen Size of the vnode on disk, if known. If unknown, give -1,
274 * and CheckLength itself will determine the on-disk size.
276 * @return operation status
277 * @retval 0 lengths match
278 * @retval nonzero Error; either the lengths do not match or there was an
279 * error determining the on-disk size. The volume should be
280 * taken offline and salvaged.
283 CheckLength(struct Volume
*vp
, struct Vnode
*vnp
, afs_sfsize_t alen
)
286 VN_GET_LEN(vlen
, vnp
);
291 fdP
= IH_OPEN(vnp
->handle
);
293 ViceLog(0, ("CheckLength: cannot open inode for fid %" AFS_VOLID_FMT
".%lu.%lu\n",
294 afs_printable_VolumeId_lu(vp
->hashid
),
295 afs_printable_uint32_lu(Vn_id(vnp
)),
296 afs_printable_uint32_lu(vnp
->disk
.uniquifier
)));
299 alen
= FDH_SIZE(fdP
);
302 afs_int64 alen64
= alen
;
303 ViceLog(0, ("CheckLength: cannot get size for inode for fid %"
304 AFS_VOLID_FMT
".%lu.%lu; FDH_SIZE returned %" AFS_INT64_FMT
"\n",
305 afs_printable_VolumeId_lu(vp
->hashid
),
306 afs_printable_uint32_lu(Vn_id(vnp
)),
307 afs_printable_uint32_lu(vnp
->disk
.uniquifier
),
314 afs_int64 alen64
= alen
, vlen64
= vlen
;
315 ViceLog(0, ("Fid %" AFS_VOLID_FMT
".%lu.%lu has inconsistent length (index "
316 "%lld inode %lld ); volume must be salvaged\n",
317 afs_printable_VolumeId_lu(vp
->hashid
),
318 afs_printable_uint32_lu(Vn_id(vnp
)),
319 afs_printable_uint32_lu(vnp
->disk
.uniquifier
),
327 LogClientError(const char *message
, struct rx_connection
*tcon
, afs_int32 viceid
, struct AFSFid
*Fid
)
331 ViceLog(0, ("%s while handling request from host %s:%d viceid %d "
332 "fid %" AFS_VOLID_FMT
".%lu.%lu, failing request\n",
334 afs_inet_ntoa_r(rx_HostOf(rx_PeerOf(tcon
)), hoststr
),
335 (int)ntohs(rx_PortOf(rx_PeerOf(tcon
))),
337 afs_printable_VolumeId_lu(Fid
->Volume
),
338 afs_printable_uint32_lu(Fid
->Vnode
),
339 afs_printable_uint32_lu(Fid
->Unique
)));
341 ViceLog(0, ("%s while handling request from host %s:%d viceid %d "
342 "fid (none), failing request\n",
344 afs_inet_ntoa_r(rx_HostOf(rx_PeerOf(tcon
)), hoststr
),
345 (int)ntohs(rx_PortOf(rx_PeerOf(tcon
))),
351 * Note that this function always returns a held host, so
352 * that CallPostamble can block without the host's disappearing.
353 * Call returns rx connection in passed in *tconn
355 * 'Fid' is optional, and is just used for printing log messages.
358 CallPreamble(struct rx_call
*acall
, int activecall
, struct AFSFid
*Fid
,
359 struct rx_connection
**tconn
, struct host
**ahostp
)
362 struct client
*tclient
;
363 afs_int32 viceid
= -1;
366 char hoststr
[16], hoststr2
[16];
367 struct ubik_client
*uclient
;
371 ViceLog(0, ("CallPreamble: unexpected null tconn!\n"));
374 *tconn
= rx_ConnectionOf(acall
);
378 tclient
= h_FindClient_r(*tconn
, &viceid
);
381 LogClientError("CallPreamble: Couldn't get client", *tconn
, viceid
, Fid
);
384 thost
= tclient
->z
.host
;
385 if (tclient
->z
.prfail
== 1) { /* couldn't get the CPS */
387 h_ReleaseClient_r(tclient
);
390 LogClientError("CallPreamble: Couldn't get CPS", *tconn
, viceid
, Fid
);
393 retry_flag
= 0; /* Retry once */
395 /* Take down the old connection and re-read the key file */
397 ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
398 uclient
= (struct ubik_client
*)pthread_getspecific(viced_uclient_key
);
400 /* Is it still necessary to drop this? We hit the net, we should... */
406 code
= hpr_Initialize(&uclient
);
409 opr_Verify(pthread_setspecific(viced_uclient_key
,
410 (void *)uclient
) == 0);
414 h_ReleaseClient_r(tclient
);
417 LogClientError("CallPreamble: couldn't reconnect to ptserver", *tconn
, viceid
, Fid
);
421 tclient
->z
.prfail
= 2; /* Means re-eval client's cps */
422 h_ReleaseClient_r(tclient
);
427 tclient
->z
.LastCall
= thost
->z
.LastCall
= time(NULL
);
428 if (activecall
) /* For all but "GetTime", "GetStats", and "GetCaps" calls */
429 thost
->z
.ActiveCall
= thost
->z
.LastCall
;
432 if (thost
->z
.hostFlags
& HOSTDELETED
) {
434 ("Discarded a packet for deleted host %s:%d\n",
435 afs_inet_ntoa_r(thost
->z
.host
, hoststr
), ntohs(thost
->z
.port
)));
436 code
= VBUSY
; /* raced, so retry */
437 } else if ((thost
->z
.hostFlags
& VENUSDOWN
)
438 || (thost
->z
.hostFlags
& HFE_LATER
)) {
439 if (BreakDelayedCallBacks_r(thost
)) {
441 ("BreakDelayedCallbacks FAILED for host %s:%d which IS UP. Connection from %s:%d. Possible network or routing failure.\n",
442 afs_inet_ntoa_r(thost
->z
.host
, hoststr
), ntohs(thost
->z
.port
), afs_inet_ntoa_r(rxr_HostOf(*tconn
), hoststr2
),
443 ntohs(rxr_PortOf(*tconn
))));
444 if (MultiProbeAlternateAddress_r(thost
)) {
446 ("MultiProbe failed to find new address for host %s:%d\n",
447 afs_inet_ntoa_r(thost
->z
.host
, hoststr
),
448 ntohs(thost
->z
.port
)));
452 ("MultiProbe found new address for host %s:%d\n",
453 afs_inet_ntoa_r(thost
->z
.host
, hoststr
),
454 ntohs(thost
->z
.port
)));
455 if (BreakDelayedCallBacks_r(thost
)) {
457 ("BreakDelayedCallbacks FAILED AGAIN for host %s:%d which IS UP. Connection from %s:%d. Possible network or routing failure.\n",
458 afs_inet_ntoa_r(thost
->z
.host
, hoststr
), ntohs(thost
->z
.port
), afs_inet_ntoa_r(rxr_HostOf(*tconn
), hoststr2
),
459 ntohs(rxr_PortOf(*tconn
))));
468 h_ReleaseClient_r(tclient
);
478 CallPostamble(struct rx_connection
*aconn
, afs_int32 ret
,
482 struct client
*tclient
;
486 tclient
= h_FindClient_r(aconn
, NULL
);
489 thost
= tclient
->z
.host
;
490 if (thost
->z
.hostFlags
& HERRORTRANS
)
492 h_ReleaseClient_r(tclient
);
495 if (ahost
!= thost
) {
496 /* host/client recycle */
497 char hoststr
[16], hoststr2
[16];
498 ViceLog(0, ("CallPostamble: ahost %s:%d (%p) != thost "
500 afs_inet_ntoa_r(ahost
->z
.host
, hoststr
),
501 ntohs(ahost
->z
.port
),
503 afs_inet_ntoa_r(thost
->z
.host
, hoststr2
),
504 ntohs(thost
->z
.port
),
507 /* return the reference taken in CallPreamble */
511 ViceLog(0, ("CallPostamble: null ahost for thost %s:%d (%p)\n",
512 afs_inet_ntoa_r(thost
->z
.host
, hoststr
),
513 ntohs(thost
->z
.port
),
517 /* return the reference taken in local h_FindClient_r--h_ReleaseClient_r
518 * does not decrement refcount on client->z.host */
523 return (translate
? sys_error_to_et(ret
) : ret
);
527 * Returns the volume and vnode pointers associated with file Fid; the lock
528 * type on the vnode is set to lock. Note that both volume/vnode's ref counts
529 * are incremented and they must be eventualy released.
532 CheckVnodeWithCall(AFSFid
* fid
, Volume
** volptr
, struct VCallByVol
*cbv
,
533 Vnode
** vptr
, int lock
)
536 Error local_errorCode
, errorCode
= -1;
537 static struct timeval restartedat
= { 0, 0 };
539 if (fid
->Volume
== 0 || fid
->Vnode
== 0) /* not: || fid->Unique == 0) */
541 if ((*volptr
) == 0) {
546 #ifdef AFS_DEMAND_ATTACH_FS
552 static const struct timespec timeout_ts
= { 0, 0 };
553 static const struct timespec
* const ts
= &timeout_ts
;
556 *volptr
= VGetVolumeWithCall(&local_errorCode
, &errorCode
,
557 fid
->Volume
, ts
, cbv
);
562 if ((errorCode
== VOFFLINE
) && (VInit
< 2)) {
563 /* The volume we want may not be attached yet because
564 * the volume initialization is not yet complete.
565 * We can do several things:
566 * 1. return -1, which will cause users to see
567 * "connection timed out". This is more or
568 * less the same as always, except that the servers
569 * may appear to bounce up and down while they
570 * are actually restarting.
571 * 2. return VBUSY which will cause clients to
572 * sleep and retry for 6.5 - 15 minutes, depending
573 * on what version of the CM they are running. If
574 * the file server takes longer than that interval
575 * to attach the desired volume, then the application
576 * will see an ENODEV or EIO. This approach has
577 * the advantage that volumes which have been attached
578 * are immediately available, it keeps the server's
579 * immediate backlog low, and the call is interruptible
580 * by the user. Users see "waiting for busy volume."
581 * 3. sleep here and retry. Some people like this approach
582 * because there is no danger of seeing errors. However,
583 * this approach only works with a bounded number of
584 * clients, since the pending queues will grow without
585 * stopping. It might be better to find a way to take
586 * this call and stick it back on a queue in order to
587 * recycle this thread for a different request.
588 * 4. Return a new error code, which new cache managers will
589 * know enough to interpret as "sleep and retry", without
590 * the upper bound of 6-15 minutes that is imposed by the
591 * VBUSY handling. Users will see "waiting for
592 * busy volume," so they know that something is
593 * happening. Old cache managers must be able to do
594 * something reasonable with this, for instance, mark the
595 * server down. Fortunately, any error code < 0
596 * will elicit that behavior. See #1.
597 * 5. Some combination of the above. I like doing #2 for 10
598 * minutes, followed by #4. 3.1b and 3.2 cache managers
599 * will be fine as long as the restart period is
600 * not longer than 6.5 minutes, otherwise they may
601 * return ENODEV to users. 3.3 cache managers will be
602 * fine for 10 minutes, then will return
603 * ETIMEDOUT. 3.4 cache managers will just wait
604 * until the call works or fails definitively.
605 * NB. The problem with 2,3,4,5 is that old clients won't
606 * fail over to an alternate read-only replica while this
607 * server is restarting. 3.4 clients will fail over right away.
609 if (restartedat
.tv_sec
== 0) {
610 /* I'm not really worried about when we restarted, I'm */
611 /* just worried about when the first VBUSY was returned. */
612 gettimeofday(&restartedat
, 0);
615 afs_perfstats
.fs_nBusies
++;
618 return (busyonrst
? VBUSY
: restarting
);
621 gettimeofday(&now
, 0);
622 if ((now
.tv_sec
- restartedat
.tv_sec
) < (11 * 60)) {
625 afs_perfstats
.fs_nBusies
++;
628 return (busyonrst
? VBUSY
: restarting
);
634 /* allow read operations on busy volume.
635 * must check local_errorCode because demand attach fs
636 * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
637 else if (local_errorCode
== VBUSY
&& lock
== READ_LOCK
) {
638 #ifdef AFS_DEMAND_ATTACH_FS
639 /* DAFS case is complicated by the fact that local_errorCode can
640 * be VBUSY in cases where the volume is truly offline */
642 /* volume is in VOL_STATE_UNATTACHED */
645 #endif /* AFS_DEMAND_ATTACH_FS */
648 } else if (errorCode
)
655 *vptr
= VGetVnode(&errorCode
, *volptr
, fid
->Vnode
, lock
);
658 if ((*vptr
)->disk
.uniquifier
!= fid
->Unique
) {
659 VPutVnode(&fileCode
, *vptr
);
660 assert_vnode_success_or_salvaging(fileCode
);
662 return (VNOVNODE
); /* return the right error code, at least */
667 static_inline afs_int32
668 CheckVnode(AFSFid
* fid
, Volume
** volptr
, Vnode
** vptr
, int lock
)
670 return CheckVnodeWithCall(fid
, volptr
, NULL
, vptr
, lock
);
674 * This routine returns the ACL associated with the targetptr. If the
675 * targetptr isn't a directory, we access its parent dir and get the ACL
676 * thru the parent; in such case the parent's vnode is returned in
680 SetAccessList(Vnode
** targetptr
, Volume
** volume
,
681 struct acl_accessList
**ACL
, int *ACLSize
, Vnode
** parent
,
682 AFSFid
* Fid
, int Lock
)
684 if ((*targetptr
)->disk
.type
== vDirectory
) {
686 *ACL
= VVnodeACL(*targetptr
);
687 *ACLSize
= VAclSize(*targetptr
);
690 opr_Assert(Fid
!= 0);
695 parentvnode
= (*targetptr
)->disk
.parent
;
696 VPutVnode(&errorCode
, *targetptr
);
700 *parent
= VGetVnode(&errorCode
, *volume
, parentvnode
, READ_LOCK
);
703 *ACL
= VVnodeACL(*parent
);
704 *ACLSize
= VAclSize(*parent
);
705 if ((errorCode
= CheckVnode(Fid
, volume
, targetptr
, Lock
)) != 0)
707 if ((*targetptr
)->disk
.parent
!= parentvnode
) {
708 VPutVnode(&errorCode
, *parent
);
719 /* Must not be called with H_LOCK held */
721 client_CheckRights(struct client
*client
, struct acl_accessList
*ACL
,
725 ObtainReadLock(&client
->lock
);
726 if (client
->z
.CPS
.prlist_len
> 0 && !client
->z
.deleted
&&
727 client
->z
.host
&& !(client
->z
.host
->z
.hostFlags
& HOSTDELETED
))
728 acl_CheckRights(ACL
, &client
->z
.CPS
, rights
);
729 ReleaseReadLock(&client
->lock
);
732 /* Must not be called with H_LOCK held */
734 client_HasAsMember(struct client
*client
, afs_int32 id
)
738 ObtainReadLock(&client
->lock
);
739 if (client
->z
.CPS
.prlist_len
> 0 && !client
->z
.deleted
&&
740 client
->z
.host
&& !(client
->z
.host
->z
.hostFlags
& HOSTDELETED
))
741 code
= acl_IsAMember(id
, &client
->z
.CPS
);
742 ReleaseReadLock(&client
->lock
);
747 * Compare the directory's ACL with the user's access rights in the client
748 * connection and return the user's and everybody else's access permissions
749 * in rights and anyrights, respectively
752 GetRights(struct client
*client
, struct acl_accessList
*ACL
,
753 afs_int32
* rights
, afs_int32
* anyrights
)
755 extern prlist SystemAnyUserCPS
;
756 afs_int32 hrights
= 0;
758 if (acl_CheckRights(ACL
, &SystemAnyUserCPS
, anyrights
) != 0) {
759 ViceLog(0, ("CheckRights failed\n"));
764 client_CheckRights(client
, ACL
, rights
);
766 /* wait if somebody else is already doing the getCPS call */
768 while (client
->z
.host
->z
.hostFlags
& HCPS_INPROGRESS
) {
769 client
->z
.host
->z
.hostFlags
|= HCPS_WAITING
; /* I am waiting */
770 opr_cv_wait(&client
->z
.host
->cond
, &host_glock_mutex
);
773 if (!client
->z
.host
->z
.hcps
.prlist_len
|| !client
->z
.host
->z
.hcps
.prlist_val
) {
776 ("CheckRights: len=%u, for host=%s:%d\n",
777 client
->z
.host
->z
.hcps
.prlist_len
,
778 afs_inet_ntoa_r(client
->z
.host
->z
.host
, hoststr
),
779 ntohs(client
->z
.host
->z
.port
)));
781 acl_CheckRights(ACL
, &client
->z
.host
->z
.hcps
, &hrights
);
783 /* Allow system:admin the rights given with the -implicit option */
784 if (client_HasAsMember(client
, SystemId
))
785 *rights
|= implicitAdminRights
;
788 *anyrights
|= hrights
;
795 * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
796 * a System:Administrator)
799 VanillaUser(struct client
*client
)
801 if (client_HasAsMember(client
, SystemId
))
802 return (0); /* not a system administrator, then you're "vanilla" */
808 /*------------------------------------------------------------------------
809 * GetVolumePackageWithCall
812 * This unusual afs_int32-parameter routine encapsulates all volume
813 * package related operations together in a single function; it's
814 * called by almost all AFS interface calls.
817 * acall : Ptr to Rx call on which this request came in.
818 * cbv : struct containing the RX call for offline cancels
819 * Fid : the AFS fid the caller is acting on
820 * volptr : returns a pointer to the volume struct
821 * targetptr : returns a pointer to the vnode struct
822 * chkforDir : whether to check for if vnode is a dir
823 * parent : returns a pointer to the parent of this vnode
824 * client : returns a pointer to the calling client
825 * locktype : indicates what kind of lock to take on vnodes
826 * rights : returns a pointer to caller's rights
827 * anyrights : returns a pointer to anonymous' rights
828 * remote : indicates that the volume is a remote RW replica
832 * appropriate error based on permission or invalid operation.
835 * Nothing interesting.
838 * On success, disables keepalives on the call. Caller should re-enable
839 * after completing disk I/O.
840 *------------------------------------------------------------------------*/
842 GetVolumePackageWithCall(struct rx_call
*acall
, struct VCallByVol
*cbv
,
843 AFSFid
* Fid
, Volume
** volptr
, Vnode
** targetptr
,
844 int chkforDir
, Vnode
** parent
,
845 struct client
**client
, int locktype
,
846 afs_int32
* rights
, afs_int32
* anyrights
, int remote
)
848 struct acl_accessList
*aCL
= NULL
; /* Internal access List */
849 int aCLSize
; /* size of the access list */
850 Error errorCode
= 0; /* return code to caller */
851 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
853 if ((errorCode
= CheckVnodeWithCall(Fid
, volptr
, cbv
, targetptr
, locktype
)))
857 if (chkforDir
== MustNOTBeDIR
858 && ((*targetptr
)->disk
.type
== vDirectory
)) {
862 else if (chkforDir
== MustBeDIR
863 && ((*targetptr
)->disk
.type
!= vDirectory
)) {
869 * If the remote flag is set, the current call is dealing with a remote RW
870 * replica, and it can be assumed that the appropriate access checks were
871 * done by the calling server hosting the master volume.
874 if ((errorCode
= SetAccessList(targetptr
, volptr
, &aCL
, &aCLSize
, parent
,
875 (chkforDir
== MustBeDIR
? (AFSFid
*) 0 : Fid
),
876 (chkforDir
== MustBeDIR
? 0 : locktype
))) != 0)
878 if (chkforDir
== MustBeDIR
)
879 opr_Assert((*parent
) == 0);
881 if ((errorCode
= GetClient(tcon
, client
)) != 0)
888 GetRights(*client
, aCL
, rights
, anyrights
);
889 /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
890 if ((*targetptr
)->disk
.type
!= vDirectory
) {
891 /* anyuser can't be owner, so only have to worry about rights, not anyrights */
892 if ((*targetptr
)->disk
.owner
== (*client
)->z
.ViceId
)
893 (*rights
) |= PRSFS_ADMINISTER
;
895 (*rights
) &= ~PRSFS_ADMINISTER
;
897 #ifdef ADMIN_IMPLICIT_LOOKUP
898 /* admins get automatic lookup on everything */
899 if (!VanillaUser(*client
))
900 (*rights
) |= PRSFS_LOOKUP
;
901 #endif /* ADMIN_IMPLICIT_LOOKUP */
906 } /*GetVolumePackage */
908 static_inline afs_int32
909 GetVolumePackage(struct rx_call
*acall
, AFSFid
* Fid
, Volume
** volptr
,
910 Vnode
** targetptr
, int chkforDir
, Vnode
** parent
,
911 struct client
**client
, int locktype
, afs_int32
* rights
,
912 afs_int32
* anyrights
)
914 return GetVolumePackageWithCall(acall
, NULL
, Fid
, volptr
, targetptr
,
915 chkforDir
, parent
, client
, locktype
,
916 rights
, anyrights
, 0);
920 /*------------------------------------------------------------------------
921 * PutVolumePackageWithCall
924 * This is the opposite of GetVolumePackage(), and is always used at
925 * the end of AFS calls to put back all used vnodes and the volume
926 * in the proper order!
929 * acall : Ptr to Rx call on which this request came in.
930 * parentwhentargetnotdir : a pointer to the parent when the target isn't
932 * targetptr : a pointer to the vnode struct
933 * parentptr : a pointer to the parent of this vnode
934 * volptr : a pointer to the volume structure
935 * client : a pointer to the calling client
936 * cbv : struct containing the RX call for offline cancels
942 * Nothing interesting.
945 * Enables keepalives on the call.
946 *------------------------------------------------------------------------*/
948 PutVolumePackageWithCall(struct rx_call
*acall
, Vnode
*
949 parentwhentargetnotdir
, Vnode
* targetptr
,
950 Vnode
* parentptr
, Volume
* volptr
,
951 struct client
**client
, struct VCallByVol
*cbv
)
953 Error fileCode
= 0; /* Error code returned by the volume package */
955 if (parentwhentargetnotdir
) {
956 VPutVnode(&fileCode
, parentwhentargetnotdir
);
957 assert_vnode_success_or_salvaging(fileCode
);
960 VPutVnode(&fileCode
, targetptr
);
961 assert_vnode_success_or_salvaging(fileCode
);
964 VPutVnode(&fileCode
, parentptr
);
965 assert_vnode_success_or_salvaging(fileCode
);
968 VPutVolumeWithCall(volptr
, cbv
);
974 } /*PutVolumePackage */
977 PutVolumePackage(struct rx_call
*acall
, Vnode
* parentwhentargetnotdir
,
978 Vnode
* targetptr
, Vnode
* parentptr
, Volume
* volptr
,
979 struct client
**client
)
981 PutVolumePackageWithCall(acall
, parentwhentargetnotdir
, targetptr
,
982 parentptr
, volptr
, client
, NULL
);
986 VolumeOwner(struct client
*client
, Vnode
* targetptr
)
988 afs_int32 owner
= V_owner(targetptr
->volumePtr
); /* get volume owner */
991 return (client
->z
.ViceId
== owner
);
994 * We don't have to check for host's cps since only regular
995 * viceid are volume owners.
997 return (client_HasAsMember(client
, owner
));
1003 VolumeRootVnode(Vnode
* targetptr
)
1005 return ((targetptr
->vnodeNumber
== ROOTVNODE
)
1006 && (targetptr
->disk
.uniquifier
== 1));
1008 } /*VolumeRootVnode */
1011 * Check if target file has the proper access permissions for the Fetch
1012 * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
1013 * StoreStatus) related calls
1015 /* this code should probably just set a "priv" flag where all the audit events
1016 * are now, and only generate the audit event once at the end of the routine,
1017 * thus only generating the event if all the checks succeed, but only because
1018 * of the privilege XXX
1021 Check_PermissionRights(Vnode
* targetptr
, struct client
*client
,
1022 afs_int32 rights
, int CallingRoutine
,
1023 AFSStoreStatus
* InStatus
)
1025 Error errorCode
= 0;
1026 #define OWNSp(client, target) ((client)->z.ViceId == (target)->disk.owner)
1027 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
1028 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
1030 if (CallingRoutine
& CHK_FETCH
) {
1031 if (CallingRoutine
== CHK_FETCHDATA
|| VanillaUser(client
)) {
1032 if (targetptr
->disk
.type
== vDirectory
1033 || targetptr
->disk
.type
== vSymlink
) {
1034 if (!(rights
& PRSFS_LOOKUP
)
1035 #ifdef ADMIN_IMPLICIT_LOOKUP
1036 /* grant admins fetch on all directories */
1037 && VanillaUser(client
)
1038 #endif /* ADMIN_IMPLICIT_LOOKUP */
1039 && !VolumeOwner(client
, targetptr
))
1042 /* must have read access, or be owner and have insert access */
1043 if (!(rights
& PRSFS_READ
)
1044 && !((OWNSp(client
, targetptr
) && (rights
& PRSFS_INSERT
)
1045 && (client
->z
.ViceId
!= AnonymousID
))))
1048 if (CallingRoutine
== CHK_FETCHDATA
1049 && targetptr
->disk
.type
== vFile
)
1050 #ifdef USE_GROUP_PERMS
1051 if (!OWNSp(client
, targetptr
)
1052 && !client_HasAsMember(client
, targetptr
->disk
.owner
)) {
1054 (((GROUPREAD
| GROUPEXEC
) & targetptr
->disk
.modeBits
)
1058 (((OWNERREAD
| OWNEREXEC
) & targetptr
->disk
.modeBits
)
1063 * The check with the ownership below is a kludge to allow
1064 * reading of files created with no read permission. The owner
1065 * of the file is always allowed to read it.
1067 if ((client
->z
.ViceId
!= targetptr
->disk
.owner
)
1068 && VanillaUser(client
))
1070 (((OWNERREAD
| OWNEREXEC
) & targetptr
->disk
.
1071 modeBits
) ? 0 : EACCES
);
1073 } else { /* !VanillaUser(client) && !FetchData */
1075 osi_audit(PrivilegeEvent
, 0, AUD_ID
,
1076 (client
? client
->z
.ViceId
: 0), AUD_INT
, CallingRoutine
,
1079 } else { /* a store operation */
1080 if ((rights
& PRSFS_INSERT
) && OWNSp(client
, targetptr
)
1081 && (CallingRoutine
!= CHK_STOREACL
)
1082 && (targetptr
->disk
.type
== vFile
)) {
1083 /* bypass protection checks on first store after a create
1084 * for the creator; also prevent chowns during this time
1085 * unless you are a system administrator */
1086 /****** InStatus->Owner && UnixModeBits better be SET!! */
1087 if (CHOWN(InStatus
, targetptr
) || CHGRP(InStatus
, targetptr
)) {
1090 else if (VanillaUser(client
))
1091 return (EPERM
); /* Was EACCES */
1093 osi_audit(PrivilegeEvent
, 0, AUD_ID
,
1094 (client
? client
->z
.ViceId
: 0), AUD_INT
,
1095 CallingRoutine
, AUD_END
);
1098 if (CallingRoutine
!= CHK_STOREDATA
&& !VanillaUser(client
)) {
1099 osi_audit(PrivilegeEvent
, 0, AUD_ID
,
1100 (client
? client
->z
.ViceId
: 0), AUD_INT
,
1101 CallingRoutine
, AUD_END
);
1103 if (readonlyServer
) {
1106 if (CallingRoutine
== CHK_STOREACL
) {
1107 if (!(rights
& PRSFS_ADMINISTER
)
1108 && !VolumeOwner(client
, targetptr
))
1110 } else { /* store data or status */
1111 /* watch for chowns and chgrps */
1112 if (CHOWN(InStatus
, targetptr
)
1113 || CHGRP(InStatus
, targetptr
)) {
1116 else if (VanillaUser(client
))
1117 return (EPERM
); /* Was EACCES */
1119 osi_audit(PrivilegeEvent
, 0, AUD_ID
,
1120 (client
? client
->z
.ViceId
: 0), AUD_INT
,
1121 CallingRoutine
, AUD_END
);
1123 /* must be sysadmin to set suid/sgid bits */
1124 if ((InStatus
->Mask
& AFS_SETMODE
) &&
1126 (InStatus
->UnixModeBits
& 0xc00) != 0) {
1128 (InStatus
->UnixModeBits
& (S_ISUID
| S_ISGID
)) != 0) {
1132 if (VanillaUser(client
))
1135 osi_audit(PrivSetID
, 0, AUD_ID
,
1136 (client
? client
->z
.ViceId
: 0), AUD_INT
,
1137 CallingRoutine
, AUD_END
);
1139 if (CallingRoutine
== CHK_STOREDATA
) {
1142 if (!(rights
& PRSFS_WRITE
))
1144 /* Next thing is tricky. We want to prevent people
1145 * from writing files sans 0200 bit, but we want
1146 * creating new files with 0444 mode to work. We
1147 * don't check the 0200 bit in the "you are the owner"
1148 * path above, but here we check the bit. However, if
1149 * you're a system administrator, we ignore the 0200
1150 * bit anyway, since you may have fchowned the file,
1152 #ifdef USE_GROUP_PERMS
1153 if ((targetptr
->disk
.type
== vFile
)
1154 && VanillaUser(client
)) {
1155 if (!OWNSp(client
, targetptr
)
1156 && !client_HasAsMember(client
, targetptr
->disk
.owner
)) {
1158 ((GROUPWRITE
& targetptr
->disk
.modeBits
)
1162 ((OWNERWRITE
& targetptr
->disk
.modeBits
)
1167 if ((targetptr
->disk
.type
!= vDirectory
)
1168 && (!(targetptr
->disk
.modeBits
& OWNERWRITE
))) {
1171 if (VanillaUser(client
))
1174 osi_audit(PrivilegeEvent
, 0, AUD_ID
,
1175 (client
? client
->z
.ViceId
: 0),
1176 AUD_INT
, CallingRoutine
, AUD_END
);
1178 } else { /* a status store */
1181 if (targetptr
->disk
.type
== vDirectory
) {
1182 if (!(rights
& PRSFS_DELETE
)
1183 && !(rights
& PRSFS_INSERT
))
1185 } else { /* a file or symlink */
1186 if (!(rights
& PRSFS_WRITE
))
1196 } /*Check_PermissionRights */
1200 * The Access List information is converted from its internal form in the
1201 * target's vnode buffer (or its parent vnode buffer if not a dir), to an
1202 * external form and returned back to the caller, via the AccessList
1206 RXFetch_AccessList(Vnode
* targetptr
, Vnode
* parentwhentargetnotdir
,
1207 struct AFSOpaque
*AccessList
)
1209 char *eACL
; /* External access list placeholder */
1211 if (acl_Externalize_pr
1212 (hpr_IdToName
, (targetptr
->disk
.type
==
1213 vDirectory
? VVnodeACL(targetptr
) :
1214 VVnodeACL(parentwhentargetnotdir
)), &eACL
) != 0) {
1217 if ((strlen(eACL
) + 1) > AFSOPAQUEMAX
) {
1218 acl_FreeExternalACL(&eACL
);
1221 strcpy((char *)(AccessList
->AFSOpaque_val
), (char *)eACL
);
1222 AccessList
->AFSOpaque_len
= strlen(eACL
) + 1;
1224 acl_FreeExternalACL(&eACL
);
1227 } /*RXFetch_AccessList */
1231 * The Access List information is converted from its external form in the
1232 * input AccessList structure to the internal representation and copied into
1233 * the target dir's vnode storage.
1236 RXStore_AccessList(Vnode
* targetptr
, struct AFSOpaque
*AccessList
)
1238 struct acl_accessList
*newACL
; /* PlaceHolder for new access list */
1240 if (acl_Internalize_pr(hpr_NameToId
, AccessList
->AFSOpaque_val
, &newACL
)
1243 if ((newACL
->size
+ 4) > VAclSize(targetptr
))
1245 memcpy((char *)VVnodeACL(targetptr
), (char *)newACL
, (int)(newACL
->size
));
1246 acl_FreeACL(&newACL
);
1249 } /*RXStore_AccessList */
1252 CheckLink(Volume
*volptr
, FdHandle_t
*fdP
, const char *descr
)
1257 code
= FDH_ISUNLINKED(fdP
);
1259 ViceLog(0, ("CopyOnWrite: error fstating volume %u inode %s (%s), errno %d\n",
1260 V_id(volptr
), PrintInode(ino
, fdP
->fd_ih
->ih_ino
), descr
, errno
));
1264 ViceLog(0, ("CopyOnWrite corruption prevention: detected zero nlink for "
1265 "volume %u inode %s (%s), forcing volume offline\n",
1266 V_id(volptr
), PrintInode(ino
, fdP
->fd_ih
->ih_ino
), descr
));
1272 /* In our current implementation, each successive data store (new file
1273 * data version) creates a new inode. This function creates the new
1274 * inode, copies the old inode's contents to the new one, remove the old
1275 * inode (i.e. decrement inode count -- if it's currently used the delete
1276 * will be delayed), and modify some fields (i.e. vnode's
1277 * disk.inodeNumber and cloned)
1279 #define COPYBUFFSIZE 8192
1280 #define MAXFSIZE (~(afs_fsize_t) 0)
1282 CopyOnWrite(Vnode
* targetptr
, Volume
* volptr
, afs_foff_t off
, afs_fsize_t len
)
1285 Inode nearInode AFS_UNUSED
;
1292 int rc
; /* return code */
1293 IHandle_t
*newH
; /* Use until finished copying, then cp to vnode. */
1294 FdHandle_t
*targFdP
; /* Source Inode file handle */
1295 FdHandle_t
*newFdP
; /* Dest Inode file handle */
1297 if (targetptr
->disk
.type
== vDirectory
)
1298 DFlush(); /* just in case? */
1300 VN_GET_LEN(size
, targetptr
);
1308 buff
= malloc(COPYBUFFSIZE
);
1313 ino
= VN_GET_INO(targetptr
);
1314 if (!VALID_INO(ino
)) {
1316 VTakeOffline(volptr
);
1317 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
1318 afs_printable_VolumeId_lu(volptr
->hashid
)));
1321 targFdP
= IH_OPEN(targetptr
->handle
);
1322 if (targFdP
== NULL
) {
1325 ("CopyOnWrite failed: Failed to open target vnode %u in volume %" AFS_VOLID_FMT
" (errno = %d)\n",
1326 targetptr
->vnodeNumber
, afs_printable_VolumeId_lu(V_id(volptr
)), rc
));
1328 VTakeOffline(volptr
);
1332 nearInode
= VN_GET_INO(targetptr
);
1334 IH_CREATE(V_linkHandle(volptr
), V_device(volptr
),
1335 VPartitionPath(V_partition(volptr
)), nearInode
,
1336 V_id(volptr
), targetptr
->vnodeNumber
,
1337 targetptr
->disk
.uniquifier
,
1338 (int)targetptr
->disk
.dataVersion
);
1339 if (!VALID_INO(ino
)) {
1341 ("CopyOnWrite failed: Partition %s that contains volume %" AFS_VOLID_FMT
" may be out of free inodes(errno = %d)\n",
1342 volptr
->partition
->name
, afs_printable_VolumeId_lu(V_id(volptr
)), errno
));
1347 IH_INIT(newH
, V_device(volptr
), V_id(volptr
), ino
);
1348 newFdP
= IH_OPEN(newH
);
1349 opr_Assert(newFdP
!= NULL
);
1351 rc
= CheckLink(volptr
, targFdP
, "source");
1353 rc
= CheckLink(volptr
, newFdP
, "dest");
1356 FDH_REALLYCLOSE(newFdP
);
1358 FDH_REALLYCLOSE(targFdP
);
1359 IH_DEC(V_linkHandle(volptr
), ino
, V_parentId(volptr
));
1361 VTakeOffline(volptr
);
1367 if (size
> COPYBUFFSIZE
) { /* more than a buffer */
1368 length
= COPYBUFFSIZE
;
1369 size
-= COPYBUFFSIZE
;
1374 rdlen
= FDH_PREAD(targFdP
, buff
, length
, done
);
1375 if (rdlen
== length
) {
1376 wrlen
= FDH_PWRITE(newFdP
, buff
, length
, done
);
1380 /* Callers of this function are not prepared to recover
1381 * from error that put the filesystem in an inconsistent
1382 * state. Make sure that we force the volume off-line if
1383 * we some error other than ENOSPC - 4.29.99)
1385 * In case we are unable to write the required bytes, and the
1386 * error code indicates that the disk is full, we roll-back to
1387 * the initial state.
1389 if ((rdlen
!= length
) || (wrlen
!= length
)) {
1390 if ((wrlen
< 0) && (errno
== ENOSPC
)) { /* disk full */
1392 ("CopyOnWrite failed: Partition %s containing volume %" AFS_VOLID_FMT
" is full\n",
1393 volptr
->partition
->name
, afs_printable_VolumeId_lu(V_id(volptr
))));
1394 /* remove destination inode which was partially copied till now */
1395 FDH_REALLYCLOSE(newFdP
);
1397 FDH_REALLYCLOSE(targFdP
);
1398 rc
= IH_DEC(V_linkHandle(volptr
), ino
, V_parentId(volptr
));
1401 ("CopyOnWrite failed: error %u after i_dec on disk full, volume %" AFS_VOLID_FMT
" in partition %s needs salvage\n",
1402 rc
, afs_printable_VolumeId_lu(V_id(volptr
)), volptr
->partition
->name
));
1403 VTakeOffline(volptr
);
1408 /* length, rdlen, and wrlen may or may not be 64-bits wide;
1409 * since we never do any I/O anywhere near 2^32 bytes at a
1410 * time, just case to an unsigned int for printing */
1413 ("CopyOnWrite failed: volume %" AFS_VOLID_FMT
" in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1414 afs_printable_VolumeId_lu(V_id(volptr
)), volptr
->partition
->name
, (unsigned)length
, (unsigned)rdlen
,
1415 (unsigned)wrlen
, errno
));
1416 #if defined(AFS_DEMAND_ATTACH_FS)
1417 ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
1419 ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
1421 /* Decrement this inode so salvager doesn't find it. */
1422 FDH_REALLYCLOSE(newFdP
);
1424 FDH_REALLYCLOSE(targFdP
);
1425 IH_DEC(V_linkHandle(volptr
), ino
, V_parentId(volptr
));
1427 VTakeOffline(volptr
);
1432 FDH_REALLYCLOSE(targFdP
);
1433 rc
= IH_DEC(V_linkHandle(volptr
), VN_GET_INO(targetptr
),
1434 V_parentId(volptr
));
1436 IH_RELEASE(targetptr
->handle
);
1438 rc
= FDH_SYNC(newFdP
);
1439 opr_Assert(rc
== 0);
1441 targetptr
->handle
= newH
;
1442 VN_SET_INO(targetptr
, ino
);
1443 targetptr
->disk
.cloned
= 0;
1444 /* Internal change to vnode, no user level change to volume - def 5445 */
1445 targetptr
->changed_oldTime
= 1;
1447 return 0; /* success */
1451 * Common code to handle with removing the Name (file when it's called from
1452 * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1453 * given directory, parentptr.
1455 int DT1
= 0, DT0
= 0;
1457 DeleteTarget(Vnode
* parentptr
, Volume
* volptr
, Vnode
** targetptr
,
1458 DirHandle
* dir
, AFSFid
* fileFid
, char *Name
, int ChkForDir
)
1460 DirHandle childdir
; /* Handle for dir package I/O */
1461 Error errorCode
= 0;
1465 /* watch for invalid names */
1466 if (!strcmp(Name
, ".") || !strcmp(Name
, ".."))
1469 if (CheckLength(volptr
, parentptr
, -1)) {
1470 VTakeOffline(volptr
);
1474 if (parentptr
->disk
.cloned
) {
1475 ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1476 if ((errorCode
= CopyOnWrite(parentptr
, volptr
, 0, MAXFSIZE
))) {
1478 ("DeleteTarget %s: CopyOnWrite failed %d\n", Name
,
1484 /* check that the file is in the directory */
1485 SetDirHandle(dir
, parentptr
);
1486 errorCode
= afs_dir_Lookup(dir
, Name
, fileFid
);
1487 if (errorCode
&& errorCode
!= ENOENT
) {
1493 fileFid
->Volume
= V_id(volptr
);
1495 /* just-in-case check for something causing deadlock */
1496 if (fileFid
->Vnode
== parentptr
->vnodeNumber
)
1499 *targetptr
= VGetVnode(&errorCode
, volptr
, fileFid
->Vnode
, WRITE_LOCK
);
1503 if (ChkForDir
== MustBeDIR
) {
1504 if ((*targetptr
)->disk
.type
!= vDirectory
)
1506 } else if ((*targetptr
)->disk
.type
== vDirectory
)
1509 /*osi_Assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
1511 * If the uniquifiers dont match then instead of asserting
1512 * take the volume offline and return VSALVAGE
1514 if ((*targetptr
)->disk
.uniquifier
!= fileFid
->Unique
) {
1515 VTakeOffline(volptr
);
1517 ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
1518 afs_printable_VolumeId_lu(volptr
->hashid
)));
1519 errorCode
= VSALVAGE
;
1523 if (ChkForDir
== MustBeDIR
) {
1524 SetDirHandle(&childdir
, *targetptr
);
1525 if (afs_dir_IsEmpty(&childdir
) != 0)
1529 (*targetptr
)->delete = 1;
1530 } else if ((--(*targetptr
)->disk
.linkCount
) == 0)
1531 (*targetptr
)->delete = 1;
1532 if ((*targetptr
)->delete) {
1533 if (VN_GET_INO(*targetptr
)) {
1535 IH_REALLYCLOSE((*targetptr
)->handle
);
1537 IH_DEC(V_linkHandle(volptr
), VN_GET_INO(*targetptr
),
1538 V_parentId(volptr
));
1539 IH_RELEASE((*targetptr
)->handle
);
1540 if (errorCode
== -1) {
1542 ("DT: inode=%s, name=%s, errno=%d\n",
1543 PrintInode(stmp
, VN_GET_INO(*targetptr
)), Name
,
1545 if (errno
!= ENOENT
)
1547 VTakeOffline(volptr
);
1549 ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
1550 afs_printable_VolumeId_lu(volptr
->hashid
)));
1557 VN_SET_INO(*targetptr
, (Inode
) 0);
1559 afs_fsize_t adjLength
;
1560 VN_GET_LEN(adjLength
, *targetptr
);
1561 VAdjustDiskUsage(&errorCode
, volptr
, -(int)nBlocks(adjLength
), 0);
1565 (*targetptr
)->changed_newTime
= 1; /* Status change of deleted file/dir */
1567 code
= afs_dir_Delete(dir
, Name
);
1570 ("Error %d deleting %s\n", code
,
1571 (((*targetptr
)->disk
.type
==
1572 Directory
) ? "directory" : "file")));
1573 VTakeOffline(volptr
);
1575 ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
1576 afs_printable_VolumeId_lu(volptr
->hashid
)));
1588 * This routine updates the parent directory's status block after the
1589 * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1590 * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1594 Update_ParentVnodeStatus(Vnode
* parentptr
, Volume
* volptr
, DirHandle
* dir
,
1595 int author
, int linkcount
, char a_inSameNetwork
)
1597 afs_fsize_t newlength
; /* Holds new directory length */
1598 afs_fsize_t parentLength
;
1600 Date currDate
; /*Current date */
1601 int writeIdx
; /*Write index to bump */
1602 int timeIdx
; /*Authorship time index to bump */
1605 parentptr
->disk
.dataVersion
++;
1606 newlength
= (afs_fsize_t
) afs_dir_Length(dir
);
1608 * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1609 * (create, symlink, link, makedir) so we need to check if we have enough space
1610 * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1611 * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1613 VN_GET_LEN(parentLength
, parentptr
);
1614 if (nBlocks(newlength
) != nBlocks(parentLength
)) {
1615 VAdjustDiskUsage(&errorCode
, volptr
,
1616 (nBlocks(newlength
) - nBlocks(parentLength
)),
1617 (nBlocks(newlength
) - nBlocks(parentLength
)));
1619 VN_SET_LEN(parentptr
, newlength
);
1622 * Update directory write stats for this volume. Note that the auth
1623 * counter is located immediately after its associated ``distance''
1626 if (a_inSameNetwork
)
1627 writeIdx
= VOL_STATS_SAME_NET
;
1629 writeIdx
= VOL_STATS_DIFF_NET
;
1630 V_stat_writes(volptr
, writeIdx
)++;
1631 if (author
!= AnonymousID
) {
1632 V_stat_writes(volptr
, writeIdx
+ 1)++;
1636 * Update the volume's authorship information in response to this
1637 * directory operation. Get the current time, decide to which time
1638 * slot this operation belongs, and bump the appropriate slot.
1641 currDate
= (now
- parentptr
->disk
.unixModifyTime
);
1643 (currDate
< VOL_STATS_TIME_CAP_0
? VOL_STATS_TIME_IDX_0
: currDate
<
1644 VOL_STATS_TIME_CAP_1
? VOL_STATS_TIME_IDX_1
: currDate
<
1645 VOL_STATS_TIME_CAP_2
? VOL_STATS_TIME_IDX_2
: currDate
<
1646 VOL_STATS_TIME_CAP_3
? VOL_STATS_TIME_IDX_3
: currDate
<
1647 VOL_STATS_TIME_CAP_4
? VOL_STATS_TIME_IDX_4
: VOL_STATS_TIME_IDX_5
);
1648 if (parentptr
->disk
.author
== author
) {
1649 V_stat_dirSameAuthor(volptr
, timeIdx
)++;
1651 V_stat_dirDiffAuthor(volptr
, timeIdx
)++;
1654 parentptr
->disk
.author
= author
;
1655 parentptr
->disk
.linkCount
= linkcount
;
1656 parentptr
->disk
.unixModifyTime
= now
; /* This should be set from CLIENT!! */
1657 parentptr
->disk
.serverModifyTime
= now
;
1658 parentptr
->changed_newTime
= 1; /* vnode changed, write it back. */
1663 * Update the target file's (or dir's) status block after the specified
1664 * operation is complete. Note that some other fields maybe updated by
1665 * the individual module.
1666 * If remote is set, the volume is a RW replica and access checks can
1670 /* XXX INCOMPLETE - More attention is needed here! */
1672 Update_TargetVnodeStatus(Vnode
* targetptr
, afs_uint32 Caller
,
1673 struct client
*client
, AFSStoreStatus
* InStatus
,
1674 Vnode
* parentptr
, Volume
* volptr
,
1675 afs_fsize_t length
, int remote
)
1677 Date currDate
; /*Current date */
1678 int writeIdx
; /*Write index to bump */
1679 int timeIdx
; /*Authorship time index to bump */
1681 if (Caller
& (TVS_CFILE
| TVS_SLINK
| TVS_MKDIR
)) { /* initialize new file */
1682 targetptr
->disk
.parent
= parentptr
->vnodeNumber
;
1683 VN_SET_LEN(targetptr
, length
);
1684 /* targetptr->disk.group = 0; save some cycles */
1685 targetptr
->disk
.modeBits
= 0777;
1686 targetptr
->disk
.owner
= client
->z
.ViceId
;
1687 targetptr
->disk
.dataVersion
= 0; /* consistent with the client */
1688 targetptr
->disk
.linkCount
= (Caller
& TVS_MKDIR
? 2 : 1);
1689 /* the inode was created in Alloc_NewVnode() */
1692 * Update file write stats for this volume. Note that the auth
1693 * counter is located immediately after its associated ``distance''
1696 if (client
->z
.InSameNetwork
)
1697 writeIdx
= VOL_STATS_SAME_NET
;
1699 writeIdx
= VOL_STATS_DIFF_NET
;
1700 V_stat_writes(volptr
, writeIdx
)++;
1701 if (client
->z
.ViceId
!= AnonymousID
) {
1702 V_stat_writes(volptr
, writeIdx
+ 1)++;
1706 * We only count operations that DON'T involve creating new objects
1707 * (files, symlinks, directories) or simply setting status as
1708 * authorship-change operations.
1710 if (!(Caller
& (TVS_CFILE
| TVS_SLINK
| TVS_MKDIR
| TVS_SSTATUS
))) {
1712 * Update the volume's authorship information in response to this
1713 * file operation. Get the current time, decide to which time
1714 * slot this operation belongs, and bump the appropriate slot.
1716 currDate
= (time(NULL
) - targetptr
->disk
.unixModifyTime
);
1719 VOL_STATS_TIME_CAP_0
? VOL_STATS_TIME_IDX_0
: currDate
<
1720 VOL_STATS_TIME_CAP_1
? VOL_STATS_TIME_IDX_1
: currDate
<
1721 VOL_STATS_TIME_CAP_2
? VOL_STATS_TIME_IDX_2
: currDate
<
1722 VOL_STATS_TIME_CAP_3
? VOL_STATS_TIME_IDX_3
: currDate
<
1723 VOL_STATS_TIME_CAP_4
? VOL_STATS_TIME_IDX_4
:
1724 VOL_STATS_TIME_IDX_5
);
1725 if (targetptr
->disk
.author
== client
->z
.ViceId
) {
1726 V_stat_fileSameAuthor(volptr
, timeIdx
)++;
1728 V_stat_fileDiffAuthor(volptr
, timeIdx
)++;
1732 if (!(Caller
& TVS_SSTATUS
))
1733 targetptr
->disk
.author
= client
->z
.ViceId
;
1734 if (Caller
& TVS_SDATA
) {
1735 targetptr
->disk
.dataVersion
++;
1736 if (!remote
&& VanillaUser(client
)) {
1738 targetptr
->disk
.modeBits
= targetptr
->disk
.modeBits
& ~04000;
1739 #ifdef CREATE_SGUID_ADMIN_ONLY
1741 targetptr
->disk
.modeBits
= targetptr
->disk
.modeBits
& ~02000;
1745 if (Caller
& TVS_SSTATUS
) { /* update time on non-status change */
1746 /* store status, must explicitly request to change the date */
1747 if (InStatus
->Mask
& AFS_SETMODTIME
)
1748 targetptr
->disk
.unixModifyTime
= InStatus
->ClientModTime
;
1749 } else { /* other: date always changes, but perhaps to what is specified by caller */
1750 targetptr
->disk
.unixModifyTime
=
1751 (InStatus
->Mask
& AFS_SETMODTIME
? InStatus
->
1752 ClientModTime
: time(NULL
));
1754 if (InStatus
->Mask
& AFS_SETOWNER
) {
1755 /* admin is allowed to do chmod, chown as well as chown, chmod. */
1756 if (!remote
&& VanillaUser(client
)) {
1758 targetptr
->disk
.modeBits
= targetptr
->disk
.modeBits
& ~04000;
1759 #ifdef CREATE_SGUID_ADMIN_ONLY
1761 targetptr
->disk
.modeBits
= targetptr
->disk
.modeBits
& ~02000;
1764 targetptr
->disk
.owner
= InStatus
->Owner
;
1765 if (VolumeRootVnode(targetptr
)) {
1766 Error errorCode
= 0; /* what should be done with this? */
1768 V_owner(targetptr
->volumePtr
) = InStatus
->Owner
;
1769 VUpdateVolume(&errorCode
, targetptr
->volumePtr
);
1772 if (InStatus
->Mask
& AFS_SETMODE
) {
1773 int modebits
= InStatus
->UnixModeBits
;
1774 #ifdef CREATE_SGUID_ADMIN_ONLY
1775 if (!remote
&& VanillaUser(client
))
1776 modebits
= modebits
& 0777;
1778 if (!remote
&& VanillaUser(client
)) {
1779 targetptr
->disk
.modeBits
= modebits
;
1781 targetptr
->disk
.modeBits
= modebits
;
1784 osi_audit(PrivSetID
, 0, AUD_ID
, client
->z
.ViceId
, AUD_INT
,
1785 CHK_STOREDATA
, AUD_END
);
1789 osi_audit(PrivSetID
, 0, AUD_ID
, client
->z
.ViceId
, AUD_INT
,
1790 CHK_STORESTATUS
, AUD_END
);
1797 targetptr
->disk
.serverModifyTime
= time(NULL
);
1798 if (InStatus
->Mask
& AFS_SETGROUP
)
1799 targetptr
->disk
.group
= InStatus
->Group
;
1800 /* vnode changed : to be written back by VPutVnode */
1801 targetptr
->changed_newTime
= 1;
1803 } /*Update_TargetVnodeStatus */
1807 * Fills the CallBack structure with the expiration time and type of callback
1808 * structure. Warning: this function is currently incomplete.
1811 SetCallBackStruct(afs_uint32 CallBackTime
, struct AFSCallBack
*CallBack
)
1813 /* CallBackTime could not be 0 */
1814 if (CallBackTime
== 0) {
1815 ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1816 CallBack
->ExpirationTime
= 0;
1818 CallBack
->ExpirationTime
= CallBackTime
- time(NULL
);
1819 CallBack
->CallBackVersion
= CALLBACK_VERSION
;
1820 CallBack
->CallBackType
= CB_SHARED
; /* The default for now */
1822 } /*SetCallBackStruct */
1826 * Adjusts (Subtract) "length" number of blocks from the volume's disk
1827 * allocation; if some error occured (exceeded volume quota or partition
1828 * was full, or whatever), it frees the space back and returns the code.
1829 * We usually pre-adjust the volume space to make sure that there's
1830 * enough space before consuming some.
1833 AdjustDiskUsage(Volume
* volptr
, afs_sfsize_t length
,
1834 afs_sfsize_t checkLength
)
1839 VAdjustDiskUsage(&rc
, volptr
, length
, checkLength
);
1841 VAdjustDiskUsage(&nc
, volptr
, -length
, 0);
1842 if (rc
== VOVERQUOTA
) {
1844 ("Volume %" AFS_VOLID_FMT
" (%s) is full\n",
1845 afs_printable_VolumeId_lu(V_id(volptr
)),
1849 if (rc
== VDISKFULL
) {
1851 ("Partition %s that contains volume %" AFS_VOLID_FMT
" is full\n",
1852 volptr
->partition
->name
,
1853 afs_printable_VolumeId_lu(V_id(volptr
))));
1856 ViceLog(0, ("Got error return %d from VAdjustDiskUsage\n", rc
));
1861 } /*AdjustDiskUsage */
1864 * Common code that handles the creation of a new file (SAFS_CreateFile and
1865 * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1868 Alloc_NewVnode(Vnode
* parentptr
, DirHandle
* dir
, Volume
* volptr
,
1869 Vnode
** targetptr
, char *Name
, struct AFSFid
*OutFid
,
1870 int FileType
, afs_sfsize_t BlocksPreallocatedForVnode
)
1872 Error errorCode
= 0; /* Error code returned back */
1875 Inode nearInode AFS_UNUSED
; /* hint for inode allocation in solaris */
1879 AdjustDiskUsage(volptr
, BlocksPreallocatedForVnode
,
1880 BlocksPreallocatedForVnode
))) {
1882 ("Insufficient space to allocate %lld blocks\n",
1883 (afs_intmax_t
) BlocksPreallocatedForVnode
));
1887 if (CheckLength(volptr
, parentptr
, -1)) {
1888 VAdjustDiskUsage(&temp
, volptr
, -BlocksPreallocatedForVnode
, 0);
1889 VTakeOffline(volptr
);
1893 *targetptr
= VAllocVnode(&errorCode
, volptr
, FileType
, 0, 0);
1894 if (errorCode
!= 0) {
1895 VAdjustDiskUsage(&temp
, volptr
, -BlocksPreallocatedForVnode
, 0);
1898 OutFid
->Volume
= V_id(volptr
);
1899 OutFid
->Vnode
= (*targetptr
)->vnodeNumber
;
1900 OutFid
->Unique
= (*targetptr
)->disk
.uniquifier
;
1902 nearInode
= VN_GET_INO(parentptr
); /* parent is also in same vol */
1904 /* create the inode now itself */
1906 IH_CREATE(V_linkHandle(volptr
), V_device(volptr
),
1907 VPartitionPath(V_partition(volptr
)), nearInode
,
1908 V_id(volptr
), (*targetptr
)->vnodeNumber
,
1909 (*targetptr
)->disk
.uniquifier
, 1);
1911 /* error in creating inode */
1912 if (!VALID_INO(inode
)) {
1914 ("Volume : %" AFS_VOLID_FMT
" vnode = %u Failed to create inode: errno = %d\n",
1915 afs_printable_VolumeId_lu(V_id((*targetptr
)->volumePtr
)),
1916 (*targetptr
)->vnodeNumber
, errno
));
1917 VAdjustDiskUsage(&temp
, volptr
, -BlocksPreallocatedForVnode
, 0);
1918 (*targetptr
)->delete = 1; /* delete vnode */
1921 VN_SET_INO(*targetptr
, inode
);
1922 IH_INIT(((*targetptr
)->handle
), V_device(volptr
), V_id(volptr
), inode
);
1924 /* copy group from parent dir */
1925 (*targetptr
)->disk
.group
= parentptr
->disk
.group
;
1927 if (parentptr
->disk
.cloned
) {
1928 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1929 if ((errorCode
= CopyOnWrite(parentptr
, volptr
, 0, MAXFSIZE
))) { /* disk full */
1930 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1931 /* delete the vnode previously allocated */
1932 (*targetptr
)->delete = 1;
1933 VAdjustDiskUsage(&temp
, volptr
, -BlocksPreallocatedForVnode
, 0);
1934 IH_REALLYCLOSE((*targetptr
)->handle
);
1935 if (IH_DEC(V_linkHandle(volptr
), inode
, V_parentId(volptr
)))
1937 ("Alloc_NewVnode: partition %s idec %s failed\n",
1938 volptr
->partition
->name
, PrintInode(stmp
, inode
)));
1939 IH_RELEASE((*targetptr
)->handle
);
1945 /* add the name to the directory */
1946 SetDirHandle(dir
, parentptr
);
1947 if ((errorCode
= afs_dir_Create(dir
, Name
, OutFid
))) {
1948 (*targetptr
)->delete = 1;
1949 VAdjustDiskUsage(&temp
, volptr
, -BlocksPreallocatedForVnode
, 0);
1950 IH_REALLYCLOSE((*targetptr
)->handle
);
1951 if (IH_DEC(V_linkHandle(volptr
), inode
, V_parentId(volptr
)))
1953 ("Alloc_NewVnode: partition %s idec %s failed\n",
1954 volptr
->partition
->name
, PrintInode(stmp
, inode
)));
1955 IH_RELEASE((*targetptr
)->handle
);
1961 } /*Alloc_NewVnode */
1965 * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1969 HandleLocking(Vnode
* targetptr
, struct client
*client
, afs_int32 rights
, ViceLockType LockingType
)
1971 int Time
; /* Used for time */
1972 int writeVnode
= targetptr
->changed_oldTime
; /* save original status */
1974 targetptr
->changed_oldTime
= 1; /* locking doesn't affect any time stamp */
1976 switch (LockingType
) {
1979 if (Time
> targetptr
->disk
.lock
.lockTime
)
1980 targetptr
->disk
.lock
.lockTime
= targetptr
->disk
.lock
.lockCount
=
1982 Time
+= AFS_LOCKWAIT
;
1983 if (LockingType
== LockRead
) {
1984 if ( !(rights
& PRSFS_LOCK
) &&
1985 !(rights
& PRSFS_WRITE
) &&
1986 !(OWNSp(client
, targetptr
) && (rights
& PRSFS_INSERT
)) )
1989 if (targetptr
->disk
.lock
.lockCount
>= 0) {
1990 ++(targetptr
->disk
.lock
.lockCount
);
1991 targetptr
->disk
.lock
.lockTime
= Time
;
1994 } else if (LockingType
== LockWrite
) {
1995 if ( !(rights
& PRSFS_WRITE
) &&
1996 !(OWNSp(client
, targetptr
) && (rights
& PRSFS_INSERT
)) )
1999 if (targetptr
->disk
.lock
.lockCount
== 0) {
2000 targetptr
->disk
.lock
.lockCount
= -1;
2001 targetptr
->disk
.lock
.lockTime
= Time
;
2007 Time
+= AFS_LOCKWAIT
;
2008 if (targetptr
->disk
.lock
.lockCount
!= 0)
2009 targetptr
->disk
.lock
.lockTime
= Time
;
2014 if ((--targetptr
->disk
.lock
.lockCount
) <= 0)
2015 targetptr
->disk
.lock
.lockCount
= targetptr
->disk
.lock
.lockTime
=
2019 targetptr
->changed_oldTime
= writeVnode
; /* restore old status */
2020 ViceLog(0, ("Illegal Locking type %d\n", LockingType
));
2023 } /*HandleLocking */
2025 /* 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. */
2028 CheckWriteMode(Vnode
* targetptr
, afs_int32 rights
, int Prfs_Mode
)
2032 if (!(rights
& Prfs_Mode
))
2034 if ((targetptr
->disk
.type
!= vDirectory
)
2035 && (!(targetptr
->disk
.modeBits
& OWNERWRITE
)))
2041 * If some flags (i.e. min or max quota) are set, the volume's in disk
2042 * label is updated; Name, OfflineMsg, and Motd are also reflected in the
2043 * update, if applicable.
2046 RXUpdate_VolumeStatus(Volume
* volptr
, AFSStoreVolumeStatus
* StoreVolStatus
,
2047 char *Name
, char *OfflineMsg
, char *Motd
)
2049 Error errorCode
= 0;
2051 if (StoreVolStatus
->Mask
& AFS_SETMINQUOTA
)
2052 V_minquota(volptr
) = StoreVolStatus
->MinQuota
;
2053 if (StoreVolStatus
->Mask
& AFS_SETMAXQUOTA
)
2054 V_maxquota(volptr
) = StoreVolStatus
->MaxQuota
;
2055 if (strlen(OfflineMsg
) > 0) {
2056 strcpy(V_offlineMessage(volptr
), OfflineMsg
);
2058 if (strlen(Name
) > 0) {
2059 strcpy(V_name(volptr
), Name
);
2062 * We don't overwrite the motd field, since it's now being used
2065 VUpdateVolume(&errorCode
, volptr
);
2068 } /*RXUpdate_VolumeStatus */
2072 RXGetVolumeStatus(AFSFetchVolumeStatus
* status
, char **name
, char **offMsg
,
2073 char **motd
, Volume
* volptr
)
2076 status
->Vid
= V_id(volptr
);
2077 status
->ParentId
= V_parentId(volptr
);
2078 status
->Online
= V_inUse(volptr
);
2079 status
->InService
= V_inService(volptr
);
2080 status
->Blessed
= V_blessed(volptr
);
2081 status
->NeedsSalvage
= V_needsSalvaged(volptr
);
2082 if (VolumeWriteable(volptr
))
2083 status
->Type
= ReadWrite
;
2085 status
->Type
= ReadOnly
;
2086 status
->MinQuota
= V_minquota(volptr
);
2087 status
->MaxQuota
= V_maxquota(volptr
);
2088 status
->BlocksInUse
= V_diskused(volptr
);
2089 status
->PartBlocksAvail
= RoundInt64ToInt31(volptr
->partition
->free
);
2090 status
->PartMaxBlocks
= RoundInt64ToInt31(volptr
->partition
->totalUsable
);
2092 /* now allocate and copy these things; they're freed by the RXGEN stub */
2093 *name
= strdup(V_name(volptr
));
2095 ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2097 *offMsg
= strdup(V_offlineMessage(volptr
));
2099 ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2103 ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2105 strcpy(*motd
, nullString
);
2107 } /*RXGetVolumeStatus */
2111 FileNameOK(char *aname
)
2116 /* watch for @sys on the right */
2117 if (strcmp(aname
+ i
- 4, "@sys") == 0)
2120 while ((tc
= *aname
++)) {
2122 return 0; /* very bad character to encounter */
2124 return 1; /* file name is ok */
2130 * This variant of symlink is expressly to support the AFS/DFS translator
2131 * and is not supported by the AFS fileserver. We just return EINVAL.
2132 * The cache manager should not generate this call to an AFS cache manager.
2135 SRXAFS_DFSSymlink(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
2136 char *LinkContents
, struct AFSStoreStatus
*InStatus
,
2137 struct AFSFid
*OutFid
, struct AFSFetchStatus
*OutFidStatus
,
2138 struct AFSFetchStatus
*OutDirStatus
,
2139 struct AFSCallBack
*CallBack
, struct AFSVolSync
*Sync
)
2145 SRXAFS_FsCmd(struct rx_call
* acall
, struct AFSFid
* Fid
,
2146 struct FsCmdInputs
* Inputs
,
2147 struct FsCmdOutputs
* Outputs
)
2151 switch (Inputs
->command
) {
2155 ViceLog(1,("FsCmd: cmd = %d, code=%d\n",
2156 Inputs
->command
, Outputs
->code
));
2161 static struct afs_buffer
{
2162 struct afs_buffer
*next
;
2163 } *freeBufferList
= 0;
2164 static int afs_buffersAlloced
= 0;
2167 FreeSendBuffer(struct afs_buffer
*adata
)
2170 afs_buffersAlloced
--;
2171 adata
->next
= freeBufferList
;
2172 freeBufferList
= adata
;
2176 } /*FreeSendBuffer */
2178 /* allocate space for sender */
2180 AllocSendBuffer(void)
2182 struct afs_buffer
*tp
;
2185 afs_buffersAlloced
++;
2186 if (!freeBufferList
) {
2189 tmp
= malloc(sendBufSize
);
2191 ViceLogThenPanic(0, ("Failed malloc in AllocSendBuffer\n"));
2195 tp
= freeBufferList
;
2196 freeBufferList
= tp
->next
;
2200 } /*AllocSendBuffer */
2201 #endif /* HAVE_PIOV */
2204 * This routine returns the status info associated with the targetptr vnode
2205 * in the AFSFetchStatus structure. Some of the newer fields, such as
2206 * SegSize and Group are not yet implemented
2210 GetStatus(Vnode
* targetptr
, AFSFetchStatus
* status
, afs_int32 rights
,
2211 afs_int32 anyrights
, Vnode
* parentptr
)
2213 int Time
= time(NULL
);
2215 /* initialize return status from a vnode */
2216 status
->InterfaceVersion
= 1;
2217 status
->SyncCounter
= status
->dataVersionHigh
= status
->lockCount
=
2218 status
->errorCode
= 0;
2219 status
->ResidencyMask
= 1; /* means for MR-AFS: file in /vicepr-partition */
2220 if (targetptr
->disk
.type
== vFile
)
2221 status
->FileType
= File
;
2222 else if (targetptr
->disk
.type
== vDirectory
)
2223 status
->FileType
= Directory
;
2224 else if (targetptr
->disk
.type
== vSymlink
)
2225 status
->FileType
= SymbolicLink
;
2227 status
->FileType
= Invalid
; /*invalid type field */
2228 status
->LinkCount
= targetptr
->disk
.linkCount
;
2230 afs_fsize_t targetLen
;
2231 VN_GET_LEN(targetLen
, targetptr
);
2232 SplitOffsetOrSize(targetLen
, status
->Length_hi
, status
->Length
);
2234 status
->DataVersion
= targetptr
->disk
.dataVersion
;
2235 status
->Author
= targetptr
->disk
.author
;
2236 status
->Owner
= targetptr
->disk
.owner
;
2237 status
->CallerAccess
= rights
;
2238 status
->AnonymousAccess
= anyrights
;
2239 status
->UnixModeBits
= targetptr
->disk
.modeBits
;
2240 status
->ClientModTime
= targetptr
->disk
.unixModifyTime
; /* This might need rework */
2241 status
->ParentVnode
=
2242 (status
->FileType
==
2243 Directory
? targetptr
->vnodeNumber
: parentptr
->vnodeNumber
);
2244 status
->ParentUnique
=
2245 (status
->FileType
==
2246 Directory
? targetptr
->disk
.uniquifier
: parentptr
->disk
.uniquifier
);
2247 status
->ServerModTime
= targetptr
->disk
.serverModifyTime
;
2248 status
->Group
= targetptr
->disk
.group
;
2249 status
->lockCount
= Time
> targetptr
->disk
.lock
.lockTime
? 0 : targetptr
->disk
.lock
.lockCount
;
2250 status
->errorCode
= 0;
2255 common_FetchData64(struct rx_call
*acall
, struct AFSFid
*Fid
,
2256 afs_sfsize_t Pos
, afs_sfsize_t Len
,
2257 struct AFSFetchStatus
*OutStatus
,
2258 struct AFSCallBack
*CallBack
, struct AFSVolSync
*Sync
,
2261 Vnode
*targetptr
= 0; /* pointer to vnode to fetch */
2262 Vnode
*parentwhentargetnotdir
= 0; /* parent vnode if vptr is a file */
2263 Vnode tparentwhentargetnotdir
; /* parent vnode for GetStatus */
2264 Error errorCode
= 0; /* return code to caller */
2265 Error fileCode
= 0; /* return code from vol package */
2266 Volume
*volptr
= 0; /* pointer to the volume */
2267 struct client
*client
= 0; /* pointer to the client data */
2268 struct rx_connection
*tcon
; /* the connection we're part of */
2270 afs_int32 rights
, anyrights
; /* rights for this and any user */
2271 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2272 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
2273 struct VCallByVol tcbv
, *cbv
= NULL
;
2274 static int remainder
= 0; /* shared access protected by FS_LOCK */
2275 struct fsstats fsstats
;
2276 afs_sfsize_t bytesToXfer
; /* # bytes to xfer */
2277 afs_sfsize_t bytesXferred
; /* # bytes actually xferred */
2278 int readIdx
; /* Index of read stats array to bump */
2280 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_FETCHDATA
);
2283 ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid
->Volume
, Fid
->Vnode
,
2286 AFSCallStats
.FetchData
++, AFSCallStats
.TotalCalls
++;
2288 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
2291 /* Get ptr to client data for user Id for logging */
2292 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2293 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
2295 ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2296 Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
2297 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
2299 queue_NodeInit(&tcbv
);
2304 * Get volume/vnode for the fetched file; caller's access rights to
2305 * it are also returned
2308 GetVolumePackageWithCall(acall
, cbv
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
2309 &parentwhentargetnotdir
, &client
, READ_LOCK
,
2310 &rights
, &anyrights
, 0)))
2313 SetVolumeSync(Sync
, volptr
);
2316 * Remember that another read operation was performed.
2319 if (client
->z
.InSameNetwork
)
2320 readIdx
= VOL_STATS_SAME_NET
;
2322 readIdx
= VOL_STATS_DIFF_NET
;
2323 V_stat_reads(volptr
, readIdx
)++;
2324 if (client
->z
.ViceId
!= AnonymousID
) {
2325 V_stat_reads(volptr
, readIdx
+ 1)++;
2328 /* Check whether the caller has permission access to fetch the data */
2330 Check_PermissionRights(targetptr
, client
, rights
, CHK_FETCHDATA
, 0)))
2334 * Drop the read lock on the parent directory after saving the parent
2335 * vnode information we need to pass to GetStatus
2337 if (parentwhentargetnotdir
!= NULL
) {
2338 tparentwhentargetnotdir
= *parentwhentargetnotdir
;
2339 VPutVnode(&fileCode
, parentwhentargetnotdir
);
2340 assert_vnode_success_or_salvaging(fileCode
);
2341 parentwhentargetnotdir
= NULL
;
2344 fsstats_StartXfer(&fsstats
, FS_STATS_XFERIDX_FETCHDATA
);
2346 /* actually do the data transfer */
2348 FetchData_RXStyle(volptr
, targetptr
, acall
, Pos
, Len
, type
,
2349 &bytesToXfer
, &bytesXferred
);
2351 fsstats_FinishXfer(&fsstats
, errorCode
, bytesToXfer
, bytesXferred
,
2357 /* write back the OutStatus from the target vnode */
2358 GetStatus(targetptr
, OutStatus
, rights
, anyrights
,
2359 &tparentwhentargetnotdir
);
2361 /* if a r/w volume, promise a callback to the caller */
2362 if (VolumeWriteable(volptr
))
2363 SetCallBackStruct(AddCallBack(client
->z
.host
, Fid
), CallBack
);
2365 struct AFSFid myFid
;
2366 memset(&myFid
, 0, sizeof(struct AFSFid
));
2367 myFid
.Volume
= Fid
->Volume
;
2368 SetCallBackStruct(AddVolCallBack(client
->z
.host
, &myFid
), CallBack
);
2372 /* Update and store volume/vnode and parent vnodes back */
2373 (void)PutVolumePackageWithCall(acall
, parentwhentargetnotdir
, targetptr
,
2374 (Vnode
*) 0, volptr
, &client
, cbv
);
2375 ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode
));
2376 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
2378 fsstats_FinishOp(&fsstats
, errorCode
);
2380 osi_auditU(acall
, FetchDataEvent
, errorCode
,
2381 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
2382 AUD_FID
, Fid
, AUD_END
);
2385 } /*SRXAFS_FetchData */
2388 SRXAFS_FetchData(struct rx_call
* acall
, struct AFSFid
* Fid
, afs_int32 Pos
,
2389 afs_int32 Len
, struct AFSFetchStatus
* OutStatus
,
2390 struct AFSCallBack
* CallBack
, struct AFSVolSync
* Sync
)
2392 return common_FetchData64(acall
, Fid
, Pos
, Len
, OutStatus
, CallBack
,
2397 SRXAFS_FetchData64(struct rx_call
* acall
, struct AFSFid
* Fid
, afs_int64 Pos
,
2398 afs_int64 Len
, struct AFSFetchStatus
* OutStatus
,
2399 struct AFSCallBack
* CallBack
, struct AFSVolSync
* Sync
)
2402 afs_sfsize_t tPos
, tLen
;
2404 tPos
= (afs_sfsize_t
) Pos
;
2405 tLen
= (afs_sfsize_t
) Len
;
2408 common_FetchData64(acall
, Fid
, tPos
, tLen
, OutStatus
, CallBack
, Sync
,
2414 SRXAFS_FetchACL(struct rx_call
* acall
, struct AFSFid
* Fid
,
2415 struct AFSOpaque
* AccessList
,
2416 struct AFSFetchStatus
* OutStatus
, struct AFSVolSync
* Sync
)
2418 Vnode
*targetptr
= 0; /* pointer to vnode to fetch */
2419 Vnode
*parentwhentargetnotdir
= 0; /* parent vnode if targetptr is a file */
2420 Error errorCode
= 0; /* return error code to caller */
2421 Volume
*volptr
= 0; /* pointer to the volume */
2422 struct client
*client
= 0; /* pointer to the client data */
2423 afs_int32 rights
, anyrights
; /* rights for this and any user */
2424 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
2426 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2427 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
2428 struct fsstats fsstats
;
2430 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_FETCHACL
);
2433 ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid
->Volume
, Fid
->Vnode
,
2436 AFSCallStats
.FetchACL
++, AFSCallStats
.TotalCalls
++;
2438 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
2441 /* Get ptr to client data for user Id for logging */
2442 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2443 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
2445 ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid
->Volume
,
2446 Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
2447 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
2449 AccessList
->AFSOpaque_len
= 0;
2450 AccessList
->AFSOpaque_val
= malloc(AFSOPAQUEMAX
);
2451 if (!AccessList
->AFSOpaque_val
) {
2452 ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2456 * Get volume/vnode for the fetched file; caller's access rights to it
2460 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
2461 &parentwhentargetnotdir
, &client
, READ_LOCK
,
2462 &rights
, &anyrights
)))
2465 SetVolumeSync(Sync
, volptr
);
2467 /* Check whether we have permission to fetch the ACL */
2469 Check_PermissionRights(targetptr
, client
, rights
, CHK_FETCHACL
, 0)))
2472 /* Get the Access List from the dir's vnode */
2474 RXFetch_AccessList(targetptr
, parentwhentargetnotdir
, AccessList
)))
2477 /* Get OutStatus back From the target Vnode */
2478 GetStatus(targetptr
, OutStatus
, rights
, anyrights
,
2479 parentwhentargetnotdir
);
2482 /* Update and store volume/vnode and parent vnodes back */
2483 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2484 (Vnode
*) 0, volptr
, &client
);
2486 ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode
,
2487 AccessList
->AFSOpaque_val
));
2488 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
2490 fsstats_FinishOp(&fsstats
, errorCode
);
2492 osi_auditU(acall
, FetchACLEvent
, errorCode
,
2493 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
2495 AUD_ACL
, AccessList
->AFSOpaque_val
, AUD_END
);
2497 } /*SRXAFS_FetchACL */
2501 * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2502 * merged into it when possible.
2505 SAFSS_FetchStatus(struct rx_call
*acall
, struct AFSFid
*Fid
,
2506 struct AFSFetchStatus
*OutStatus
,
2507 struct AFSCallBack
*CallBack
, struct AFSVolSync
*Sync
)
2509 Vnode
*targetptr
= 0; /* pointer to vnode to fetch */
2510 Vnode
*parentwhentargetnotdir
= 0; /* parent vnode if targetptr is a file */
2511 Error errorCode
= 0; /* return code to caller */
2512 Volume
*volptr
= 0; /* pointer to the volume */
2513 struct client
*client
= 0; /* pointer to the client data */
2514 afs_int32 rights
, anyrights
; /* rights for this and any user */
2515 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2516 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
2517 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
2519 /* Get ptr to client data for user Id for logging */
2520 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2521 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
2523 ("SAFS_FetchStatus, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2524 Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
2525 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
2527 AFSCallStats
.FetchStatus
++, AFSCallStats
.TotalCalls
++;
2530 * Get volume/vnode for the fetched file; caller's rights to it are
2534 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
2535 &parentwhentargetnotdir
, &client
, READ_LOCK
,
2536 &rights
, &anyrights
)))
2537 goto Bad_FetchStatus
;
2539 /* set volume synchronization information */
2540 SetVolumeSync(Sync
, volptr
);
2542 /* Are we allowed to fetch Fid's status? */
2543 if (targetptr
->disk
.type
!= vDirectory
) {
2545 Check_PermissionRights(targetptr
, client
, rights
,
2546 CHK_FETCHSTATUS
, 0))) {
2547 if (rx_GetCallAbortCode(acall
) == errorCode
)
2548 rx_SetCallAbortCode(acall
, 0);
2549 goto Bad_FetchStatus
;
2553 /* set OutStatus From the Fid */
2554 GetStatus(targetptr
, OutStatus
, rights
, anyrights
,
2555 parentwhentargetnotdir
);
2557 /* If a r/w volume, also set the CallBack state */
2558 if (VolumeWriteable(volptr
))
2559 SetCallBackStruct(AddCallBack(client
->z
.host
, Fid
), CallBack
);
2561 struct AFSFid myFid
;
2562 memset(&myFid
, 0, sizeof(struct AFSFid
));
2563 myFid
.Volume
= Fid
->Volume
;
2564 SetCallBackStruct(AddVolCallBack(client
->z
.host
, &myFid
), CallBack
);
2568 /* Update and store volume/vnode and parent vnodes back */
2569 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2570 (Vnode
*) 0, volptr
, &client
);
2571 ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode
));
2574 } /*SAFSS_FetchStatus */
2578 SRXAFS_BulkStatus(struct rx_call
* acall
, struct AFSCBFids
* Fids
,
2579 struct AFSBulkStats
* OutStats
, struct AFSCBs
* CallBacks
,
2580 struct AFSVolSync
* Sync
)
2584 Vnode
*targetptr
= 0; /* pointer to vnode to fetch */
2585 Vnode
*parentwhentargetnotdir
= 0; /* parent vnode if targetptr is a file */
2586 Error errorCode
= 0; /* return code to caller */
2587 Volume
*volptr
= 0; /* pointer to the volume */
2588 struct client
*client
= 0; /* pointer to the client data */
2589 afs_int32 rights
, anyrights
; /* rights for this and any user */
2590 struct AFSFid
*tfid
; /* file id we're dealing with now */
2591 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
2593 struct client
*t_client
= NULL
; /* tmp pointer to the client data */
2594 struct fsstats fsstats
;
2596 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_BULKSTATUS
);
2598 ViceLog(1, ("SAFS_BulkStatus\n"));
2600 AFSCallStats
.TotalCalls
++;
2602 nfiles
= Fids
->AFSCBFids_len
; /* # of files in here */
2603 if (nfiles
<= 0) { /* Sanity check */
2605 goto Audit_and_Return
;
2608 /* allocate space for return output parameters */
2609 OutStats
->AFSBulkStats_val
= malloc(nfiles
* sizeof(struct AFSFetchStatus
));
2610 if (!OutStats
->AFSBulkStats_val
) {
2611 ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2613 OutStats
->AFSBulkStats_len
= nfiles
;
2614 CallBacks
->AFSCBs_val
= malloc(nfiles
* sizeof(struct AFSCallBack
));
2615 if (!CallBacks
->AFSCBs_val
) {
2616 ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2618 CallBacks
->AFSCBs_len
= nfiles
;
2620 tfid
= Fids
->AFSCBFids_val
;
2622 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, tfid
, &tcon
, &thost
)))
2623 goto Bad_BulkStatus
;
2625 for (i
= 0; i
< nfiles
; i
++, tfid
++) {
2627 * Get volume/vnode for the fetched file; caller's rights to it
2631 GetVolumePackage(acall
, tfid
, &volptr
, &targetptr
, DONTCHECK
,
2632 &parentwhentargetnotdir
, &client
, READ_LOCK
,
2633 &rights
, &anyrights
)))
2634 goto Bad_BulkStatus
;
2636 /* set volume synchronization information, but only once per call */
2638 SetVolumeSync(Sync
, volptr
);
2640 /* Are we allowed to fetch Fid's status? */
2641 if (targetptr
->disk
.type
!= vDirectory
) {
2643 Check_PermissionRights(targetptr
, client
, rights
,
2644 CHK_FETCHSTATUS
, 0))) {
2645 if (rx_GetCallAbortCode(acall
) == errorCode
)
2646 rx_SetCallAbortCode(acall
, 0);
2647 goto Bad_BulkStatus
;
2651 /* set OutStatus From the Fid */
2652 GetStatus(targetptr
, &OutStats
->AFSBulkStats_val
[i
], rights
,
2653 anyrights
, parentwhentargetnotdir
);
2655 /* If a r/w volume, also set the CallBack state */
2656 if (VolumeWriteable(volptr
))
2657 SetCallBackStruct(AddBulkCallBack(client
->z
.host
, tfid
),
2658 &CallBacks
->AFSCBs_val
[i
]);
2660 struct AFSFid myFid
;
2661 memset(&myFid
, 0, sizeof(struct AFSFid
));
2662 myFid
.Volume
= tfid
->Volume
;
2663 SetCallBackStruct(AddVolCallBack(client
->z
.host
, &myFid
),
2664 &CallBacks
->AFSCBs_val
[i
]);
2667 /* put back the file ID and volume */
2668 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2669 (Vnode
*) 0, volptr
, &client
);
2670 parentwhentargetnotdir
= (Vnode
*) 0;
2671 targetptr
= (Vnode
*) 0;
2672 volptr
= (Volume
*) 0;
2673 client
= (struct client
*)0;
2677 /* Update and store volume/vnode and parent vnodes back */
2678 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2679 (Vnode
*) 0, volptr
, &client
);
2680 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
2682 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2684 fsstats_FinishOp(&fsstats
, errorCode
);
2687 ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode
));
2688 osi_auditU(acall
, BulkFetchStatusEvent
, errorCode
,
2689 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
2690 AUD_FIDS
, Fids
, AUD_END
);
2693 } /*SRXAFS_BulkStatus */
2697 SRXAFS_InlineBulkStatus(struct rx_call
* acall
, struct AFSCBFids
* Fids
,
2698 struct AFSBulkStats
* OutStats
,
2699 struct AFSCBs
* CallBacks
, struct AFSVolSync
* Sync
)
2703 Vnode
*targetptr
= 0; /* pointer to vnode to fetch */
2704 Vnode
*parentwhentargetnotdir
= 0; /* parent vnode if targetptr is a file */
2705 Error errorCode
= 0; /* return code to caller */
2706 Volume
*volptr
= 0; /* pointer to the volume */
2707 struct client
*client
= 0; /* pointer to the client data */
2708 afs_int32 rights
, anyrights
; /* rights for this and any user */
2709 struct AFSFid
*tfid
; /* file id we're dealing with now */
2710 struct rx_connection
*tcon
;
2712 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2713 AFSFetchStatus
*tstatus
;
2714 int VolSync_set
= 0;
2715 struct fsstats fsstats
;
2717 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_BULKSTATUS
);
2719 ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2721 AFSCallStats
.TotalCalls
++;
2723 nfiles
= Fids
->AFSCBFids_len
; /* # of files in here */
2724 if (nfiles
<= 0) { /* Sanity check */
2726 goto Audit_and_Return
;
2729 /* allocate space for return output parameters */
2730 OutStats
->AFSBulkStats_val
= calloc(nfiles
, sizeof(struct AFSFetchStatus
));
2731 if (!OutStats
->AFSBulkStats_val
) {
2732 ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2734 OutStats
->AFSBulkStats_len
= nfiles
;
2735 CallBacks
->AFSCBs_val
= calloc(nfiles
, sizeof(struct AFSCallBack
));
2736 if (!CallBacks
->AFSCBs_val
) {
2737 ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2739 CallBacks
->AFSCBs_len
= nfiles
;
2741 /* Zero out return values to avoid leaking information on partial succes */
2742 memset(Sync
, 0, sizeof(*Sync
));
2744 tfid
= Fids
->AFSCBFids_val
;
2746 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, tfid
, &tcon
, &thost
))) {
2747 goto Bad_InlineBulkStatus
;
2750 for (i
= 0; i
< nfiles
; i
++, tfid
++) {
2752 * Get volume/vnode for the fetched file; caller's rights to it
2756 GetVolumePackage(acall
, tfid
, &volptr
, &targetptr
, DONTCHECK
,
2757 &parentwhentargetnotdir
, &client
, READ_LOCK
,
2758 &rights
, &anyrights
))) {
2759 tstatus
= &OutStats
->AFSBulkStats_val
[i
];
2761 tstatus
->InterfaceVersion
= 1;
2762 if (thost
->z
.hostFlags
& HERRORTRANS
) {
2763 tstatus
->errorCode
= sys_error_to_et(errorCode
);
2765 tstatus
->errorCode
= errorCode
;
2768 PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2769 (Vnode
*) 0, volptr
, &client
);
2770 parentwhentargetnotdir
= (Vnode
*) 0;
2771 targetptr
= (Vnode
*) 0;
2772 volptr
= (Volume
*) 0;
2773 client
= (struct client
*)0;
2777 /* set volume synchronization information, but only once per call */
2779 SetVolumeSync(Sync
, volptr
);
2783 /* Are we allowed to fetch Fid's status? */
2784 if (targetptr
->disk
.type
!= vDirectory
) {
2786 Check_PermissionRights(targetptr
, client
, rights
,
2787 CHK_FETCHSTATUS
, 0))) {
2788 tstatus
= &OutStats
->AFSBulkStats_val
[i
];
2790 tstatus
->InterfaceVersion
= 1;
2791 if (thost
->z
.hostFlags
& HERRORTRANS
) {
2792 tstatus
->errorCode
= sys_error_to_et(errorCode
);
2794 tstatus
->errorCode
= errorCode
;
2797 (void)PutVolumePackage(acall
, parentwhentargetnotdir
,
2798 targetptr
, (Vnode
*) 0, volptr
,
2800 parentwhentargetnotdir
= (Vnode
*) 0;
2801 targetptr
= (Vnode
*) 0;
2802 volptr
= (Volume
*) 0;
2803 client
= (struct client
*)0;
2808 /* set OutStatus From the Fid */
2809 GetStatus(targetptr
,
2810 (struct AFSFetchStatus
*)&OutStats
->AFSBulkStats_val
[i
],
2811 rights
, anyrights
, parentwhentargetnotdir
);
2813 /* If a r/w volume, also set the CallBack state */
2814 if (VolumeWriteable(volptr
))
2815 SetCallBackStruct(AddBulkCallBack(client
->z
.host
, tfid
),
2816 &CallBacks
->AFSCBs_val
[i
]);
2818 struct AFSFid myFid
;
2819 memset(&myFid
, 0, sizeof(struct AFSFid
));
2820 myFid
.Volume
= tfid
->Volume
;
2821 SetCallBackStruct(AddVolCallBack(client
->z
.host
, &myFid
),
2822 &CallBacks
->AFSCBs_val
[i
]);
2825 /* put back the file ID and volume */
2826 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2827 (Vnode
*) 0, volptr
, &client
);
2828 parentwhentargetnotdir
= (Vnode
*) 0;
2829 targetptr
= (Vnode
*) 0;
2830 volptr
= (Volume
*) 0;
2831 client
= (struct client
*)0;
2835 Bad_InlineBulkStatus
:
2836 /* Update and store volume/vnode and parent vnodes back */
2837 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2838 (Vnode
*) 0, volptr
, &client
);
2839 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
2841 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2843 fsstats_FinishOp(&fsstats
, errorCode
);
2846 ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode
));
2847 osi_auditU(acall
, InlineBulkFetchStatusEvent
, errorCode
,
2848 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
2849 AUD_FIDS
, Fids
, AUD_END
);
2852 } /*SRXAFS_InlineBulkStatus */
2856 SRXAFS_FetchStatus(struct rx_call
* acall
, struct AFSFid
* Fid
,
2857 struct AFSFetchStatus
* OutStatus
,
2858 struct AFSCallBack
* CallBack
, struct AFSVolSync
* Sync
)
2861 struct rx_connection
*tcon
;
2863 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2864 struct fsstats fsstats
;
2866 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_FETCHSTATUS
);
2868 if ((code
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
2869 goto Bad_FetchStatus
;
2871 code
= SAFSS_FetchStatus(acall
, Fid
, OutStatus
, CallBack
, Sync
);
2874 code
= CallPostamble(tcon
, code
, thost
);
2876 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2878 fsstats_FinishOp(&fsstats
, code
);
2880 osi_auditU(acall
, FetchStatusEvent
, code
,
2881 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
2882 AUD_FID
, Fid
, AUD_END
);
2885 } /*SRXAFS_FetchStatus */
2889 common_StoreData64(struct rx_call
*acall
, struct AFSFid
*Fid
,
2890 struct AFSStoreStatus
*InStatus
, afs_fsize_t Pos
,
2891 afs_fsize_t Length
, afs_fsize_t FileLength
,
2892 struct AFSFetchStatus
*OutStatus
, struct AFSVolSync
*Sync
)
2894 Vnode
*targetptr
= 0; /* pointer to input fid */
2895 Vnode
*parentwhentargetnotdir
= 0; /* parent of Fid to get ACL */
2896 Vnode tparentwhentargetnotdir
; /* parent vnode for GetStatus */
2897 Error errorCode
= 0; /* return code for caller */
2898 Error fileCode
= 0; /* return code from vol package */
2899 Volume
*volptr
= 0; /* pointer to the volume header */
2900 struct client
*client
= 0; /* pointer to client structure */
2901 afs_int32 rights
, anyrights
; /* rights for this and any user */
2902 struct client
*t_client
= NULL
; /* tmp ptr to client data */
2903 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
2904 struct rx_connection
*tcon
;
2906 struct fsstats fsstats
;
2907 afs_sfsize_t bytesToXfer
;
2908 afs_sfsize_t bytesXferred
;
2909 static int remainder
= 0;
2912 ("StoreData: Fid = %u.%u.%u\n", Fid
->Volume
, Fid
->Vnode
,
2915 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_STOREDATA
);
2918 AFSCallStats
.StoreData
++, AFSCallStats
.TotalCalls
++;
2920 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
2923 /* Get ptr to client data for user Id for logging */
2924 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2925 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
2927 ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid
->Volume
,
2928 Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
2929 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
2932 * Get associated volume/vnode for the stored file; caller's rights
2936 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, MustNOTBeDIR
,
2937 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
2938 &rights
, &anyrights
))) {
2942 /* set volume synchronization information */
2943 SetVolumeSync(Sync
, volptr
);
2945 if (targetptr
->disk
.type
== vSymlink
) {
2946 /* Should we return a better error code here??? */
2951 /* Check if we're allowed to store the data */
2953 Check_PermissionRights(targetptr
, client
, rights
, CHK_STOREDATA
,
2959 * Drop the read lock on the parent directory after saving the parent
2960 * vnode information we need to pass to GetStatus
2962 if (parentwhentargetnotdir
!= NULL
) {
2963 tparentwhentargetnotdir
= *parentwhentargetnotdir
;
2964 VPutVnode(&fileCode
, parentwhentargetnotdir
);
2965 assert_vnode_success_or_salvaging(fileCode
);
2966 parentwhentargetnotdir
= NULL
;
2969 fsstats_StartXfer(&fsstats
, FS_STATS_XFERIDX_STOREDATA
);
2972 StoreData_RXStyle(volptr
, targetptr
, Fid
, client
, acall
, Pos
, Length
,
2973 FileLength
, (InStatus
->Mask
& AFS_FSYNC
),
2974 &bytesToXfer
, &bytesXferred
);
2976 fsstats_FinishXfer(&fsstats
, errorCode
, bytesToXfer
, bytesXferred
,
2979 if (errorCode
&& (!targetptr
->changed_newTime
))
2982 /* Update the status of the target's vnode */
2983 Update_TargetVnodeStatus(targetptr
, TVS_SDATA
, client
, InStatus
,
2984 targetptr
, volptr
, 0, 0);
2986 /* Get the updated File's status back to the caller */
2987 GetStatus(targetptr
, OutStatus
, rights
, anyrights
,
2988 &tparentwhentargetnotdir
);
2991 /* Update and store volume/vnode and parent vnodes back */
2992 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
2993 (Vnode
*) 0, volptr
, &client
);
2994 ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode
));
2996 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
2998 fsstats_FinishOp(&fsstats
, errorCode
);
3000 osi_auditU(acall
, StoreDataEvent
, errorCode
,
3001 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
3002 AUD_FID
, Fid
, AUD_END
);
3004 } /*common_StoreData64 */
3007 SRXAFS_StoreData(struct rx_call
* acall
, struct AFSFid
* Fid
,
3008 struct AFSStoreStatus
* InStatus
, afs_uint32 Pos
,
3009 afs_uint32 Length
, afs_uint32 FileLength
,
3010 struct AFSFetchStatus
* OutStatus
, struct AFSVolSync
* Sync
)
3012 if (FileLength
> 0x7fffffff || Pos
> 0x7fffffff ||
3013 (0x7fffffff - Pos
) < Length
)
3016 return common_StoreData64(acall
, Fid
, InStatus
, Pos
, Length
, FileLength
,
3018 } /*SRXAFS_StoreData */
3021 SRXAFS_StoreData64(struct rx_call
* acall
, struct AFSFid
* Fid
,
3022 struct AFSStoreStatus
* InStatus
, afs_uint64 Pos
,
3023 afs_uint64 Length
, afs_uint64 FileLength
,
3024 struct AFSFetchStatus
* OutStatus
,
3025 struct AFSVolSync
* Sync
)
3029 afs_fsize_t tLength
;
3030 afs_fsize_t tFileLength
;
3032 tPos
= (afs_fsize_t
) Pos
;
3033 tLength
= (afs_fsize_t
) Length
;
3034 tFileLength
= (afs_fsize_t
) FileLength
;
3037 common_StoreData64(acall
, Fid
, InStatus
, tPos
, tLength
, tFileLength
,
3043 SRXAFS_StoreACL(struct rx_call
* acall
, struct AFSFid
* Fid
,
3044 struct AFSOpaque
* AccessList
,
3045 struct AFSFetchStatus
* OutStatus
, struct AFSVolSync
* Sync
)
3047 Vnode
*targetptr
= 0; /* pointer to input fid */
3048 Vnode
*parentwhentargetnotdir
= 0; /* parent of Fid to get ACL */
3049 Error errorCode
= 0; /* return code for caller */
3050 struct AFSStoreStatus InStatus
; /* Input status for fid */
3051 Volume
*volptr
= 0; /* pointer to the volume header */
3052 struct client
*client
= 0; /* pointer to client structure */
3053 afs_int32 rights
, anyrights
; /* rights for this and any user */
3054 struct rx_connection
*tcon
;
3056 struct client
*t_client
= NULL
; /* tmp ptr to client data */
3057 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
3058 struct fsstats fsstats
;
3060 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_STOREACL
);
3062 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
3065 /* Get ptr to client data for user Id for logging */
3066 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3067 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
3069 ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3070 Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
, AccessList
->AFSOpaque_val
,
3071 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
3073 AFSCallStats
.StoreACL
++, AFSCallStats
.TotalCalls
++;
3075 InStatus
.Mask
= 0; /* not storing any status */
3078 * Get associated volume/vnode for the target dir; caller's rights
3079 * are also returned.
3082 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, MustBeDIR
,
3083 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
3084 &rights
, &anyrights
))) {
3088 /* set volume synchronization information */
3089 SetVolumeSync(Sync
, volptr
);
3091 /* Check if we have permission to change the dir's ACL */
3093 Check_PermissionRights(targetptr
, client
, rights
, CHK_STOREACL
,
3098 /* Build and store the new Access List for the dir */
3099 if ((errorCode
= RXStore_AccessList(targetptr
, AccessList
))) {
3103 targetptr
->changed_newTime
= 1; /* status change of directory */
3105 /* convert the write lock to a read lock before breaking callbacks */
3106 VVnodeWriteToRead(&errorCode
, targetptr
);
3107 assert_vnode_success_or_salvaging(errorCode
);
3109 /* break call backs on the directory */
3110 BreakCallBack(client
->z
.host
, Fid
, 0);
3112 /* Get the updated dir's status back to the caller */
3113 GetStatus(targetptr
, OutStatus
, rights
, anyrights
, 0);
3116 /* Update and store volume/vnode and parent vnodes back */
3117 PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, (Vnode
*) 0,
3119 ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode
));
3120 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
3122 fsstats_FinishOp(&fsstats
, errorCode
);
3124 osi_auditU(acall
, StoreACLEvent
, errorCode
,
3125 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
3126 AUD_FID
, Fid
, AUD_ACL
, AccessList
->AFSOpaque_val
, AUD_END
);
3129 } /*SRXAFS_StoreACL */
3133 * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3134 * should be merged when possible.
3137 SAFSS_StoreStatus(struct rx_call
*acall
, struct AFSFid
*Fid
,
3138 struct AFSStoreStatus
*InStatus
,
3139 struct AFSFetchStatus
*OutStatus
, struct AFSVolSync
*Sync
)
3141 Vnode
*targetptr
= 0; /* pointer to input fid */
3142 Vnode
*parentwhentargetnotdir
= 0; /* parent of Fid to get ACL */
3143 Error errorCode
= 0; /* return code for caller */
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 client
*t_client
= NULL
; /* tmp ptr to client data */
3148 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
3149 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
3151 /* Get ptr to client data for user Id for logging */
3152 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3153 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
3155 ("SAFS_StoreStatus, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
3156 Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
3157 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
3159 AFSCallStats
.StoreStatus
++, AFSCallStats
.TotalCalls
++;
3162 * Get volume/vnode for the target file; caller's rights to it are
3166 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
3167 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
3168 &rights
, &anyrights
))) {
3169 goto Bad_StoreStatus
;
3172 /* set volume synchronization information */
3173 SetVolumeSync(Sync
, volptr
);
3175 /* Check if the caller has proper permissions to store status to Fid */
3177 Check_PermissionRights(targetptr
, client
, rights
, CHK_STORESTATUS
,
3179 goto Bad_StoreStatus
;
3182 * Check for a symbolic link; we can't chmod these (otherwise could
3183 * change a symlink to a mt pt or vice versa)
3185 if (targetptr
->disk
.type
== vSymlink
&& (InStatus
->Mask
& AFS_SETMODE
)) {
3187 goto Bad_StoreStatus
;
3190 /* Update the status of the target's vnode */
3191 Update_TargetVnodeStatus(targetptr
, TVS_SSTATUS
, client
, InStatus
,
3192 (parentwhentargetnotdir
? parentwhentargetnotdir
3193 : targetptr
), volptr
, 0, 0);
3195 /* convert the write lock to a read lock before breaking callbacks */
3196 VVnodeWriteToRead(&errorCode
, targetptr
);
3197 assert_vnode_success_or_salvaging(errorCode
);
3199 /* Break call backs on Fid */
3200 BreakCallBack(client
->z
.host
, Fid
, 0);
3202 /* Return the updated status back to caller */
3203 GetStatus(targetptr
, OutStatus
, rights
, anyrights
,
3204 parentwhentargetnotdir
);
3207 /* Update and store volume/vnode and parent vnodes back */
3208 PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, (Vnode
*) 0,
3210 ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode
));
3213 } /*SAFSS_StoreStatus */
3217 SRXAFS_StoreStatus(struct rx_call
* acall
, struct AFSFid
* Fid
,
3218 struct AFSStoreStatus
* InStatus
,
3219 struct AFSFetchStatus
* OutStatus
,
3220 struct AFSVolSync
* Sync
)
3223 struct rx_connection
*tcon
;
3225 struct client
*t_client
= NULL
; /* tmp ptr to client data */
3226 struct fsstats fsstats
;
3228 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_STORESTATUS
);
3230 if ((code
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
3231 goto Bad_StoreStatus
;
3233 code
= SAFSS_StoreStatus(acall
, Fid
, InStatus
, OutStatus
, Sync
);
3236 code
= CallPostamble(tcon
, code
, thost
);
3238 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3240 fsstats_FinishOp(&fsstats
, code
);
3242 osi_auditU(acall
, StoreStatusEvent
, code
,
3243 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
3244 AUD_FID
, Fid
, AUD_END
);
3247 } /*SRXAFS_StoreStatus */
3251 * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3252 * merged in when possible.
3255 SAFSS_RemoveFile(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
3256 struct AFSFetchStatus
*OutDirStatus
, struct AFSVolSync
*Sync
)
3258 Vnode
*parentptr
= 0; /* vnode of input Directory */
3259 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
3260 Vnode
*targetptr
= 0; /* file to be deleted */
3261 Volume
*volptr
= 0; /* pointer to the volume header */
3262 AFSFid fileFid
; /* area for Fid from the directory */
3263 Error errorCode
= 0; /* error code */
3264 DirHandle dir
; /* Handle for dir package I/O */
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
; /* tmp ptr to client data */
3268 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
3269 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
3272 /* Get ptr to client data for user Id for logging */
3273 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3274 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
3276 ("SAFS_RemoveFile %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name
,
3277 DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
3278 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
3280 AFSCallStats
.RemoveFile
++, AFSCallStats
.TotalCalls
++;
3283 * Get volume/vnode for the parent dir; caller's access rights are
3287 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
3288 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
3289 &rights
, &anyrights
))) {
3290 goto Bad_RemoveFile
;
3292 /* set volume synchronization information */
3293 SetVolumeSync(Sync
, volptr
);
3295 /* Does the caller has delete (& write) access to the parent directory? */
3296 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_DELETE
))) {
3297 goto Bad_RemoveFile
;
3300 /* Actually delete the desired file */
3302 DeleteTarget(parentptr
, volptr
, &targetptr
, &dir
, &fileFid
, Name
,
3304 goto Bad_RemoveFile
;
3307 /* Update the vnode status of the parent dir */
3308 Update_ParentVnodeStatus(parentptr
, volptr
, &dir
, client
->z
.ViceId
,
3309 parentptr
->disk
.linkCount
,
3310 client
->z
.InSameNetwork
);
3312 /* Return the updated parent dir's status back to caller */
3313 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, 0);
3315 /* Handle internal callback state for the parent and the deleted file */
3316 if (targetptr
->disk
.linkCount
== 0) {
3317 /* no references left, discard entry */
3318 DeleteFileCallBacks(&fileFid
);
3319 /* convert the parent lock to a read lock before breaking callbacks */
3320 VVnodeWriteToRead(&errorCode
, parentptr
);
3321 assert_vnode_success_or_salvaging(errorCode
);
3323 /* convert the parent lock to a read lock before breaking callbacks */
3324 VVnodeWriteToRead(&errorCode
, parentptr
);
3325 assert_vnode_success_or_salvaging(errorCode
);
3326 /* convert the target lock to a read lock before breaking callbacks */
3327 VVnodeWriteToRead(&errorCode
, targetptr
);
3328 assert_vnode_success_or_salvaging(errorCode
);
3329 /* tell all the file has changed */
3330 BreakCallBack(client
->z
.host
, &fileFid
, 1);
3333 /* break call back on the directory */
3334 BreakCallBack(client
->z
.host
, DirFid
, 0);
3337 /* Update and store volume/vnode and parent vnodes back */
3338 PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
3341 ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode
));
3344 } /*SAFSS_RemoveFile */
3348 SRXAFS_RemoveFile(struct rx_call
* acall
, struct AFSFid
* DirFid
, char *Name
,
3349 struct AFSFetchStatus
* OutDirStatus
,
3350 struct AFSVolSync
* Sync
)
3353 struct rx_connection
*tcon
;
3355 struct client
*t_client
= NULL
; /* tmp ptr to client data */
3356 struct fsstats fsstats
;
3358 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_REMOVEFILE
);
3360 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
3361 goto Bad_RemoveFile
;
3363 code
= SAFSS_RemoveFile(acall
, DirFid
, Name
, OutDirStatus
, Sync
);
3366 code
= CallPostamble(tcon
, code
, thost
);
3368 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3370 fsstats_FinishOp(&fsstats
, code
);
3372 osi_auditU(acall
, RemoveFileEvent
, code
,
3373 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
3374 AUD_FID
, DirFid
, AUD_STR
, Name
, AUD_END
);
3377 } /*SRXAFS_RemoveFile */
3381 * This routine is called exclusively from SRXAFS_CreateFile(), and should
3382 * be merged in when possible.
3385 SAFSS_CreateFile(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
3386 struct AFSStoreStatus
*InStatus
, struct AFSFid
*OutFid
,
3387 struct AFSFetchStatus
*OutFidStatus
,
3388 struct AFSFetchStatus
*OutDirStatus
,
3389 struct AFSCallBack
*CallBack
, struct AFSVolSync
*Sync
)
3391 Vnode
*parentptr
= 0; /* vnode of input Directory */
3392 Vnode
*targetptr
= 0; /* vnode of the new file */
3393 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
3394 Volume
*volptr
= 0; /* pointer to the volume header */
3395 Error errorCode
= 0; /* error code */
3396 DirHandle dir
; /* Handle for dir package I/O */
3397 struct client
*client
= 0; /* pointer to client structure */
3398 afs_int32 rights
, anyrights
; /* rights for this and any user */
3399 struct client
*t_client
; /* tmp ptr to client data */
3400 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
3401 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
3405 /* Get ptr to client data for user Id for logging */
3406 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3407 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
3409 ("SAFS_CreateFile %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name
,
3410 DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
3411 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
3413 AFSCallStats
.CreateFile
++, AFSCallStats
.TotalCalls
++;
3415 if (!FileNameOK(Name
)) {
3417 goto Bad_CreateFile
;
3421 * Get associated volume/vnode for the parent dir; caller long are
3425 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
3426 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
3427 &rights
, &anyrights
))) {
3428 goto Bad_CreateFile
;
3431 /* set volume synchronization information */
3432 SetVolumeSync(Sync
, volptr
);
3434 /* Can we write (and insert) onto the parent directory? */
3435 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_INSERT
))) {
3436 goto Bad_CreateFile
;
3439 /* get a new vnode for the file to be created and set it up */
3441 Alloc_NewVnode(parentptr
, &dir
, volptr
, &targetptr
, Name
, OutFid
,
3442 vFile
, nBlocks(0))))
3443 goto Bad_CreateFile
;
3445 /* update the status of the parent vnode */
3446 Update_ParentVnodeStatus(parentptr
, volptr
, &dir
, client
->z
.ViceId
,
3447 parentptr
->disk
.linkCount
,
3448 client
->z
.InSameNetwork
);
3450 /* update the status of the new file's vnode */
3451 Update_TargetVnodeStatus(targetptr
, TVS_CFILE
, client
, InStatus
,
3452 parentptr
, volptr
, 0, 0);
3454 /* set up the return status for the parent dir and the newly created file, and since the newly created file is owned by the creator, give it PRSFS_ADMINISTER to tell the client its the owner of the file */
3455 GetStatus(targetptr
, OutFidStatus
, rights
| PRSFS_ADMINISTER
, anyrights
, parentptr
);
3456 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, 0);
3458 /* convert the write lock to a read lock before breaking callbacks */
3459 VVnodeWriteToRead(&errorCode
, parentptr
);
3460 assert_vnode_success_or_salvaging(errorCode
);
3462 /* break call back on parent dir */
3463 BreakCallBack(client
->z
.host
, DirFid
, 0);
3465 /* Return a callback promise for the newly created file to the caller */
3466 SetCallBackStruct(AddCallBack(client
->z
.host
, OutFid
), CallBack
);
3469 /* Update and store volume/vnode and parent vnodes back */
3470 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
3473 ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode
));
3476 } /*SAFSS_CreateFile */
3480 SRXAFS_CreateFile(struct rx_call
* acall
, struct AFSFid
* DirFid
, char *Name
,
3481 struct AFSStoreStatus
* InStatus
, struct AFSFid
* OutFid
,
3482 struct AFSFetchStatus
* OutFidStatus
,
3483 struct AFSFetchStatus
* OutDirStatus
,
3484 struct AFSCallBack
* CallBack
, struct AFSVolSync
* Sync
)
3487 struct rx_connection
*tcon
;
3489 struct client
*t_client
= NULL
; /* tmp ptr to client data */
3490 struct fsstats fsstats
;
3492 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_CREATEFILE
);
3494 memset(OutFid
, 0, sizeof(struct AFSFid
));
3496 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
3497 goto Bad_CreateFile
;
3500 SAFSS_CreateFile(acall
, DirFid
, Name
, InStatus
, OutFid
, OutFidStatus
,
3501 OutDirStatus
, CallBack
, Sync
);
3504 code
= CallPostamble(tcon
, code
, thost
);
3506 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3508 fsstats_FinishOp(&fsstats
, code
);
3510 osi_auditU(acall
, CreateFileEvent
, code
,
3511 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
3512 AUD_FID
, DirFid
, AUD_STR
, Name
, AUD_FID
, OutFid
, AUD_END
);
3515 } /*SRXAFS_CreateFile */
3519 * This routine is called exclusively from SRXAFS_Rename(), and should be
3520 * merged in when possible.
3523 SAFSS_Rename(struct rx_call
*acall
, struct AFSFid
*OldDirFid
, char *OldName
,
3524 struct AFSFid
*NewDirFid
, char *NewName
,
3525 struct AFSFetchStatus
*OutOldDirStatus
,
3526 struct AFSFetchStatus
*OutNewDirStatus
, struct AFSVolSync
*Sync
)
3528 Vnode
*oldvptr
= 0; /* vnode of the old Directory */
3529 Vnode
*newvptr
= 0; /* vnode of the new Directory */
3530 Vnode
*fileptr
= 0; /* vnode of the file to move */
3531 Vnode
*newfileptr
= 0; /* vnode of the file to delete */
3532 Vnode
*testvptr
= 0; /* used in directory tree walk */
3533 Vnode
*parent
= 0; /* parent for use in SetAccessList */
3534 Error errorCode
= 0; /* error code */
3535 Error fileCode
= 0; /* used when writing Vnodes */
3536 VnodeId testnode
; /* used in directory tree walk */
3537 AFSFid fileFid
; /* Fid of file to move */
3538 AFSFid newFileFid
; /* Fid of new file */
3539 DirHandle olddir
; /* Handle for dir package I/O */
3540 DirHandle newdir
; /* Handle for dir package I/O */
3541 DirHandle filedir
; /* Handle for dir package I/O */
3542 DirHandle newfiledir
; /* Handle for dir package I/O */
3543 Volume
*volptr
= 0; /* pointer to the volume header */
3544 struct client
*client
= 0; /* pointer to client structure */
3545 afs_int32 rights
, anyrights
; /* rights for this and any user */
3546 afs_int32 newrights
; /* rights for this user */
3547 afs_int32 newanyrights
; /* rights for any user */
3548 int doDelete
; /* deleted the rename target (ref count now 0) */
3550 int updatefile
= 0; /* are we changing the renamed file? (we do this
3551 * if we need to update .. on a renamed dir) */
3552 struct client
*t_client
; /* tmp ptr to client data */
3553 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
3554 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
3560 FidZero(&newfiledir
);
3562 /* Get ptr to client data for user Id for logging */
3563 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
3564 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
3566 ("SAFS_Rename %s to %s, Fid = %u.%u.%u to %u.%u.%u, Host %s:%d, Id %d\n",
3567 OldName
, NewName
, OldDirFid
->Volume
, OldDirFid
->Vnode
,
3568 OldDirFid
->Unique
, NewDirFid
->Volume
, NewDirFid
->Vnode
,
3569 NewDirFid
->Unique
, inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
3571 AFSCallStats
.Rename
++, AFSCallStats
.TotalCalls
++;
3573 if (!FileNameOK(NewName
)) {
3577 if (OldDirFid
->Volume
!= NewDirFid
->Volume
) {
3582 if ((strcmp(OldName
, ".") == 0) || (strcmp(OldName
, "..") == 0)
3583 || (strcmp(NewName
, ".") == 0) || (strcmp(NewName
, "..") == 0)
3584 || (strlen(NewName
) == 0) || (strlen(OldName
) == 0)) {
3590 if (OldDirFid
->Vnode
<= NewDirFid
->Vnode
) {
3592 GetVolumePackage(acall
, OldDirFid
, &volptr
, &oldvptr
, MustBeDIR
,
3593 &parent
, &client
, WRITE_LOCK
, &rights
,
3598 if (OldDirFid
->Vnode
== NewDirFid
->Vnode
) {
3600 newrights
= rights
, newanyrights
= anyrights
;
3603 GetVolumePackage(acall
, NewDirFid
, &volptr
, &newvptr
,
3604 MustBeDIR
, &parent
, &client
, WRITE_LOCK
,
3605 &newrights
, &newanyrights
))) {
3611 GetVolumePackage(acall
, NewDirFid
, &volptr
, &newvptr
, MustBeDIR
,
3612 &parent
, &client
, WRITE_LOCK
, &newrights
,
3618 GetVolumePackage(acall
, OldDirFid
, &volptr
, &oldvptr
, MustBeDIR
,
3619 &parent
, &client
, WRITE_LOCK
, &rights
,
3626 /* set volume synchronization information */
3627 SetVolumeSync(Sync
, volptr
);
3629 if ((errorCode
= CheckWriteMode(oldvptr
, rights
, PRSFS_DELETE
))) {
3632 if ((errorCode
= CheckWriteMode(newvptr
, newrights
, PRSFS_INSERT
))) {
3636 if (CheckLength(volptr
, oldvptr
, -1) ||
3637 CheckLength(volptr
, newvptr
, -1)) {
3638 VTakeOffline(volptr
);
3639 errorCode
= VSALVAGE
;
3643 /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3644 * call to CopyOnWrite returns error, it is not necessary to revert back
3645 * the effects of the first call because the contents of the volume is
3646 * not modified, it is only replicated.
3648 if (oldvptr
->disk
.cloned
) {
3649 ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n"));
3650 if ((errorCode
= CopyOnWrite(oldvptr
, volptr
, 0, MAXFSIZE
)))
3653 SetDirHandle(&olddir
, oldvptr
);
3654 if (newvptr
->disk
.cloned
) {
3655 ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n"));
3656 if ((errorCode
= CopyOnWrite(newvptr
, volptr
, 0, MAXFSIZE
)))
3660 SetDirHandle(&newdir
, newvptr
);
3662 /* Lookup the file to delete its vnode */
3663 errorCode
= afs_dir_Lookup(&olddir
, OldName
, &fileFid
);
3664 if (errorCode
&& errorCode
!= ENOENT
) {
3670 if (fileFid
.Vnode
== oldvptr
->vnodeNumber
3671 || fileFid
.Vnode
== newvptr
->vnodeNumber
) {
3672 errorCode
= FSERR_ELOOP
;
3675 fileFid
.Volume
= V_id(volptr
);
3676 fileptr
= VGetVnode(&errorCode
, volptr
, fileFid
.Vnode
, WRITE_LOCK
);
3677 if (errorCode
!= 0) {
3679 ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n",
3680 OldName
, errorCode
));
3681 VTakeOffline(volptr
);
3684 if (fileptr
->disk
.uniquifier
!= fileFid
.Unique
) {
3686 ("SAFSS_Rename(): Old file %s uniquifier mismatch\n",
3688 VTakeOffline(volptr
);
3693 if (fileptr
->disk
.type
!= vDirectory
&& oldvptr
!= newvptr
3694 && fileptr
->disk
.linkCount
!= 1) {
3696 * Hard links exist to this file - cannot move one of the links to
3697 * a new directory because of AFS restrictions (this is the same
3698 * reason that links cannot be made across directories, i.e.
3705 /* Lookup the new file */
3706 code
= afs_dir_Lookup(&newdir
, NewName
, &newFileFid
);
3707 if (code
&& code
!= ENOENT
) {
3712 if (readonlyServer
) {
3713 errorCode
= VREADONLY
;
3716 if (!(newrights
& PRSFS_DELETE
)) {
3720 if (newFileFid
.Vnode
== oldvptr
->vnodeNumber
3721 || newFileFid
.Vnode
== newvptr
->vnodeNumber
3722 || newFileFid
.Vnode
== fileFid
.Vnode
) {
3726 newFileFid
.Volume
= V_id(volptr
);
3728 VGetVnode(&errorCode
, volptr
, newFileFid
.Vnode
, WRITE_LOCK
);
3729 if (errorCode
!= 0) {
3731 ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n",
3732 NewName
, errorCode
));
3733 VTakeOffline(volptr
);
3736 if (fileptr
->disk
.uniquifier
!= fileFid
.Unique
) {
3738 ("SAFSS_Rename(): New file %s uniquifier mismatch\n",
3740 VTakeOffline(volptr
);
3744 SetDirHandle(&newfiledir
, newfileptr
);
3745 /* Now check that we're moving directories over directories properly, etc.
3746 * return proper POSIX error codes:
3747 * if fileptr is a file and new is a dir: EISDIR.
3748 * if fileptr is a dir and new is a file: ENOTDIR.
3749 * Also, dir to be removed must be empty, of course.
3751 if (newfileptr
->disk
.type
== vDirectory
) {
3752 if (fileptr
->disk
.type
!= vDirectory
) {
3756 if ((afs_dir_IsEmpty(&newfiledir
))) {
3761 if (fileptr
->disk
.type
== vDirectory
) {
3762 errorCode
= ENOTDIR
;
3769 * ok - now we check that the old name is not above new name in the
3770 * directory structure. This is to prevent removing a subtree alltogether
3772 if ((oldvptr
!= newvptr
) && (fileptr
->disk
.type
== vDirectory
)) {
3773 afs_int32 forpass
= 0, vnum
= 0, top
= 0;
3774 for (testnode
= newvptr
->disk
.parent
; testnode
!= 0; forpass
++) {
3775 if (testnode
> vnum
) vnum
= testnode
;
3776 if (forpass
> vnum
) {
3777 errorCode
= FSERR_ELOOP
;
3780 if (testnode
== oldvptr
->vnodeNumber
) {
3781 testnode
= oldvptr
->disk
.parent
;
3784 if ((testnode
== fileptr
->vnodeNumber
)
3785 || (testnode
== newvptr
->vnodeNumber
)) {
3786 errorCode
= FSERR_ELOOP
;
3789 if ((newfileptr
) && (testnode
== newfileptr
->vnodeNumber
)) {
3790 errorCode
= FSERR_ELOOP
;
3793 if (testnode
== 1) top
= 1;
3794 testvptr
= VGetVnode(&errorCode
, volptr
, testnode
, READ_LOCK
);
3795 assert_vnode_success_or_salvaging(errorCode
);
3796 testnode
= testvptr
->disk
.parent
;
3797 VPutVnode(&errorCode
, testvptr
);
3798 if ((top
== 1) && (testnode
!= 0)) {
3799 VTakeOffline(volptr
);
3801 ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
3802 afs_printable_VolumeId_lu(volptr
->hashid
)));
3806 assert_vnode_success_or_salvaging(errorCode
);
3810 if (fileptr
->disk
.type
== vDirectory
) {
3811 SetDirHandle(&filedir
, fileptr
);
3812 if (oldvptr
!= newvptr
) {
3813 /* we always need to update .. if we've moving fileptr to a
3814 * different directory */
3817 struct AFSFid unused
;
3819 code
= afs_dir_Lookup(&filedir
, "..", &unused
);
3820 if (code
&& code
!= ENOENT
) {
3824 if (code
== ENOENT
) {
3825 /* only update .. if it doesn't already exist */
3831 /* Do the CopyonWrite first before modifying anything else. Copying is
3832 * required when we have to change entries for ..
3834 if (updatefile
&& (fileptr
->disk
.cloned
)) {
3835 ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n"));
3836 if ((errorCode
= CopyOnWrite(fileptr
, volptr
, 0, MAXFSIZE
)))
3838 /* since copyonwrite would mean fileptr has a new handle, do it here */
3840 SetDirHandle(&filedir
, fileptr
);
3843 /* If the new name exists already, delete it and the file it points to */
3846 /* Delete NewName from its directory */
3847 code
= afs_dir_Delete(&newdir
, NewName
);
3848 opr_Assert(code
== 0);
3850 /* Drop the link count */
3851 newfileptr
->disk
.linkCount
--;
3852 if (newfileptr
->disk
.linkCount
== 0) { /* Link count 0 - delete */
3853 afs_fsize_t newSize
;
3854 VN_GET_LEN(newSize
, newfileptr
);
3855 VAdjustDiskUsage((Error
*) & errorCode
, volptr
,
3856 (afs_sfsize_t
) - nBlocks(newSize
), 0);
3857 if (VN_GET_INO(newfileptr
)) {
3858 IH_REALLYCLOSE(newfileptr
->handle
);
3860 IH_DEC(V_linkHandle(volptr
), VN_GET_INO(newfileptr
),
3861 V_parentId(volptr
));
3862 IH_RELEASE(newfileptr
->handle
);
3863 if (errorCode
== -1) {
3865 ("Del: inode=%s, name=%s, errno=%d\n",
3866 PrintInode(stmp
, VN_GET_INO(newfileptr
)),
3868 if ((errno
!= ENOENT
) && (errno
!= EIO
)
3869 && (errno
!= ENXIO
))
3870 ViceLog(0, ("Do we need to fsck?\n"));
3873 VN_SET_INO(newfileptr
, (Inode
) 0);
3874 newfileptr
->delete = 1; /* Mark NewName vnode to delete */
3877 /* Link count did not drop to zero.
3878 * Mark NewName vnode as changed - updates stime.
3880 newfileptr
->changed_newTime
= 1;
3885 * If the create below fails, and the delete above worked, we have
3886 * removed the new name and not replaced it. This is not very likely,
3887 * but possible. We could try to put the old file back, but it is
3888 * highly unlikely that it would work since it would involve issuing
3891 if ((errorCode
= afs_dir_Create(&newdir
, NewName
, &fileFid
)))
3894 /* Delete the old name */
3895 opr_Assert(afs_dir_Delete(&olddir
, OldName
) == 0);
3897 /* if the directory length changes, reflect it in the statistics */
3898 Update_ParentVnodeStatus(oldvptr
, volptr
, &olddir
, client
->z
.ViceId
,
3899 oldvptr
->disk
.linkCount
, client
->z
.InSameNetwork
);
3900 Update_ParentVnodeStatus(newvptr
, volptr
, &newdir
, client
->z
.ViceId
,
3901 newvptr
->disk
.linkCount
, client
->z
.InSameNetwork
);
3903 if (oldvptr
== newvptr
)
3904 oldvptr
->disk
.dataVersion
--; /* Since it was bumped by 2! */
3906 if (fileptr
->disk
.parent
!= newvptr
->vnodeNumber
) {
3907 fileptr
->disk
.parent
= newvptr
->vnodeNumber
;
3908 fileptr
->changed_newTime
= 1;
3911 /* if we are dealing with a rename of a directory, and we need to
3912 * update the .. entry of that directory */
3914 opr_Assert(!fileptr
->disk
.cloned
);
3916 fileptr
->changed_newTime
= 1; /* status change of moved file */
3918 /* fix .. to point to the correct place */
3919 afs_dir_Delete(&filedir
, ".."); /* No assert--some directories may be bad */
3920 opr_Assert(afs_dir_Create(&filedir
, "..", NewDirFid
) == 0);
3921 fileptr
->disk
.dataVersion
++;
3923 /* if the parent directories are different the link counts have to be */
3924 /* changed due to .. in the renamed directory */
3925 if (oldvptr
!= newvptr
) {
3926 oldvptr
->disk
.linkCount
--;
3927 newvptr
->disk
.linkCount
++;
3931 /* set up return status */
3932 GetStatus(oldvptr
, OutOldDirStatus
, rights
, anyrights
, 0);
3933 GetStatus(newvptr
, OutNewDirStatus
, newrights
, newanyrights
, 0);
3934 if (newfileptr
&& doDelete
) {
3935 DeleteFileCallBacks(&newFileFid
); /* no other references */
3940 /* convert the write locks to a read locks before breaking callbacks */
3941 VVnodeWriteToRead(&errorCode
, newvptr
);
3942 assert_vnode_success_or_salvaging(errorCode
);
3943 if (oldvptr
!= newvptr
) {
3944 VVnodeWriteToRead(&errorCode
, oldvptr
);
3945 assert_vnode_success_or_salvaging(errorCode
);
3947 if (newfileptr
&& !doDelete
) {
3948 /* convert the write lock to a read lock before breaking callbacks */
3949 VVnodeWriteToRead(&errorCode
, newfileptr
);
3950 assert_vnode_success_or_salvaging(errorCode
);
3953 /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */
3954 BreakCallBack(client
->z
.host
, NewDirFid
, 0);
3955 if (oldvptr
!= newvptr
) {
3956 BreakCallBack(client
->z
.host
, OldDirFid
, 0);
3959 /* if a dir moved, .. changed */
3960 /* we do not give an AFSFetchStatus structure back to the
3961 * originating client, and the file's status has changed, so be
3962 * sure to send a callback break. In theory the client knows
3963 * enough to know that the callback could be broken implicitly,
3964 * but that may not be clear, and some client implementations
3965 * may not know to. */
3966 BreakCallBack(client
->z
.host
, &fileFid
, 1);
3969 /* Note: it is not necessary to break the callback */
3971 DeleteFileCallBacks(&newFileFid
); /* no other references */
3973 /* other's still exist (with wrong link count) */
3974 BreakCallBack(client
->z
.host
, &newFileFid
, 1);
3979 VPutVnode(&fileCode
, newfileptr
);
3980 assert_vnode_success_or_salvaging(fileCode
);
3982 (void)PutVolumePackage(acall
, fileptr
, (newvptr
&& newvptr
!= oldvptr
?
3983 newvptr
: 0), oldvptr
, volptr
, &client
);
3987 FidZap(&newfiledir
);
3988 ViceLog(2, ("SAFS_Rename returns %d\n", errorCode
));
3995 SRXAFS_Rename(struct rx_call
* acall
, struct AFSFid
* OldDirFid
,
3996 char *OldName
, struct AFSFid
* NewDirFid
, char *NewName
,
3997 struct AFSFetchStatus
* OutOldDirStatus
,
3998 struct AFSFetchStatus
* OutNewDirStatus
,
3999 struct AFSVolSync
* Sync
)
4002 struct rx_connection
*tcon
;
4004 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4005 struct fsstats fsstats
;
4007 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_RENAME
);
4009 if ((code
= CallPreamble(acall
, ACTIVECALL
, OldDirFid
, &tcon
, &thost
)))
4013 SAFSS_Rename(acall
, OldDirFid
, OldName
, NewDirFid
, NewName
,
4014 OutOldDirStatus
, OutNewDirStatus
, Sync
);
4017 code
= CallPostamble(tcon
, code
, thost
);
4019 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4021 fsstats_FinishOp(&fsstats
, code
);
4023 osi_auditU(acall
, RenameFileEvent
, code
,
4024 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4025 AUD_FID
, OldDirFid
, AUD_STR
, OldName
,
4026 AUD_FID
, NewDirFid
, AUD_STR
, NewName
, AUD_END
);
4029 } /*SRXAFS_Rename */
4033 * This routine is called exclusively by SRXAFS_Symlink(), and should be
4034 * merged into it when possible.
4037 SAFSS_Symlink(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
4038 char *LinkContents
, struct AFSStoreStatus
*InStatus
,
4039 struct AFSFid
*OutFid
, struct AFSFetchStatus
*OutFidStatus
,
4040 struct AFSFetchStatus
*OutDirStatus
, struct AFSVolSync
*Sync
)
4042 Vnode
*parentptr
= 0; /* vnode of input Directory */
4043 Vnode
*targetptr
= 0; /* vnode of the new link */
4044 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4045 Error errorCode
= 0; /* error code */
4048 DirHandle dir
; /* Handle for dir package I/O */
4049 Volume
*volptr
= 0; /* pointer to the volume header */
4050 struct client
*client
= 0; /* pointer to client structure */
4051 afs_int32 rights
, anyrights
; /* rights for this and any user */
4052 struct client
*t_client
; /* tmp ptr to client data */
4053 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4055 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4059 /* Get ptr to client data for user Id for logging */
4060 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4061 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4063 ("SAFS_Symlink %s to %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name
,
4064 LinkContents
, DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
4065 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4067 AFSCallStats
.Symlink
++, AFSCallStats
.TotalCalls
++;
4069 if (!FileNameOK(Name
)) {
4075 * Get the vnode and volume for the parent dir along with the caller's
4079 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
4080 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4081 &rights
, &anyrights
)))
4084 /* set volume synchronization information */
4085 SetVolumeSync(Sync
, volptr
);
4087 /* Does the caller has insert (and write) access to the parent directory? */
4088 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_INSERT
)))
4092 * If we're creating a mount point (any x bits clear), we must have
4093 * administer access to the directory, too. Always allow sysadmins
4096 if ((InStatus
->Mask
& AFS_SETMODE
) && !(InStatus
->UnixModeBits
& 0111)) {
4097 if (readonlyServer
) {
4098 errorCode
= VREADONLY
;
4102 * We have a mountpoint, 'cause we're trying to set the Unix mode
4103 * bits to something with some x bits missing (default mode bits
4104 * if AFS_SETMODE is false is 0777)
4106 if (VanillaUser(client
) && !(rights
& PRSFS_ADMINISTER
)) {
4112 /* get a new vnode for the symlink and set it up */
4114 Alloc_NewVnode(parentptr
, &dir
, volptr
, &targetptr
, Name
, OutFid
,
4115 vSymlink
, nBlocks(strlen((char *)LinkContents
))))) {
4119 /* update the status of the parent vnode */
4120 Update_ParentVnodeStatus(parentptr
, volptr
, &dir
, client
->z
.ViceId
,
4121 parentptr
->disk
.linkCount
,
4122 client
->z
.InSameNetwork
);
4124 /* update the status of the new symbolic link file vnode */
4125 Update_TargetVnodeStatus(targetptr
, TVS_SLINK
, client
, InStatus
,
4126 parentptr
, volptr
, strlen((char *)LinkContents
), 0);
4128 /* Write the contents of the symbolic link name into the target inode */
4129 fdP
= IH_OPEN(targetptr
->handle
);
4131 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
4132 parentptr
, volptr
, &client
);
4133 VTakeOffline(volptr
);
4134 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
4135 afs_printable_VolumeId_lu(volptr
->hashid
)));
4138 len
= strlen((char *) LinkContents
);
4139 code
= (len
== FDH_PWRITE(fdP
, (char *) LinkContents
, len
, 0)) ? 0 : VDISKFULL
;
4141 ViceLog(0, ("SAFSS_Symlink FDH_PWRITE failed for len=%d, Fid=%u.%d.%d\n", (int)len
, OutFid
->Volume
, OutFid
->Vnode
, OutFid
->Unique
));
4144 * Set up and return modified status for the parent dir and new symlink
4147 GetStatus(targetptr
, OutFidStatus
, rights
, anyrights
, parentptr
);
4148 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, 0);
4150 /* convert the write lock to a read lock before breaking callbacks */
4151 VVnodeWriteToRead(&errorCode
, parentptr
);
4152 assert_vnode_success_or_salvaging(errorCode
);
4154 /* break call back on the parent dir */
4155 BreakCallBack(client
->z
.host
, DirFid
, 0);
4158 /* Write the all modified vnodes (parent, new files) and volume back */
4159 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
4162 ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode
));
4163 return ( errorCode
? errorCode
: code
);
4165 } /*SAFSS_Symlink */
4169 SRXAFS_Symlink(struct rx_call
*acall
, /* Rx call */
4170 struct AFSFid
*DirFid
, /* Parent dir's fid */
4171 char *Name
, /* File name to create */
4172 char *LinkContents
, /* Contents of the new created file */
4173 struct AFSStoreStatus
*InStatus
, /* Input status for the new symbolic link */
4174 struct AFSFid
*OutFid
, /* Fid for newly created symbolic link */
4175 struct AFSFetchStatus
*OutFidStatus
, /* Output status for new symbolic link */
4176 struct AFSFetchStatus
*OutDirStatus
, /* Output status for parent dir */
4177 struct AFSVolSync
*Sync
)
4180 struct rx_connection
*tcon
;
4182 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4183 struct fsstats fsstats
;
4185 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_SYMLINK
);
4187 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
4191 SAFSS_Symlink(acall
, DirFid
, Name
, LinkContents
, InStatus
, OutFid
,
4192 OutFidStatus
, OutDirStatus
, Sync
);
4195 code
= CallPostamble(tcon
, code
, thost
);
4197 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4199 fsstats_FinishOp(&fsstats
, code
);
4201 osi_auditU(acall
, SymlinkEvent
, code
,
4202 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4203 AUD_FID
, DirFid
, AUD_STR
, Name
,
4204 AUD_FID
, OutFid
, AUD_STR
, LinkContents
, AUD_END
);
4207 } /*SRXAFS_Symlink */
4211 * This routine is called exclusively by SRXAFS_Link(), and should be
4212 * merged into it when possible.
4215 SAFSS_Link(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
4216 struct AFSFid
*ExistingFid
, struct AFSFetchStatus
*OutFidStatus
,
4217 struct AFSFetchStatus
*OutDirStatus
, struct AFSVolSync
*Sync
)
4219 Vnode
*parentptr
= 0; /* vnode of input Directory */
4220 Vnode
*targetptr
= 0; /* vnode of the new file */
4221 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4222 Volume
*volptr
= 0; /* pointer to the volume header */
4223 Error errorCode
= 0; /* error code */
4224 DirHandle dir
; /* Handle for dir package I/O */
4225 struct client
*client
= 0; /* pointer to client structure */
4226 afs_int32 rights
, anyrights
; /* rights for this and any user */
4227 struct client
*t_client
; /* tmp ptr to client data */
4228 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4229 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4233 /* Get ptr to client data for user Id for logging */
4234 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4235 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4237 ("SAFS_Link %s, Did = %u.%u.%u, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
4238 Name
, DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
4239 ExistingFid
->Volume
, ExistingFid
->Vnode
, ExistingFid
->Unique
,
4240 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4242 AFSCallStats
.Link
++, AFSCallStats
.TotalCalls
++;
4244 if (DirFid
->Volume
!= ExistingFid
->Volume
) {
4248 if (!FileNameOK(Name
)) {
4254 * Get the vnode and volume for the parent dir along with the caller's
4258 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
4259 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4260 &rights
, &anyrights
))) {
4264 /* set volume synchronization information */
4265 SetVolumeSync(Sync
, volptr
);
4267 /* Can the caller insert into the parent directory? */
4268 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_INSERT
))) {
4272 if (((DirFid
->Vnode
& 1) && (ExistingFid
->Vnode
& 1)) || (DirFid
->Vnode
== ExistingFid
->Vnode
)) { /* at present, */
4273 /* AFS fileservers always have directory vnodes that are odd. */
4278 if (CheckLength(volptr
, parentptr
, -1)) {
4279 VTakeOffline(volptr
);
4280 errorCode
= VSALVAGE
;
4284 /* get the file vnode */
4286 CheckVnode(ExistingFid
, &volptr
, &targetptr
, WRITE_LOCK
))) {
4290 if (targetptr
->disk
.type
!= vFile
) {
4294 if (targetptr
->disk
.parent
!= DirFid
->Vnode
) {
4298 if (parentptr
->disk
.cloned
) {
4299 ViceLog(25, ("Link : calling CopyOnWrite on target dir\n"));
4300 if ((errorCode
= CopyOnWrite(parentptr
, volptr
, 0, MAXFSIZE
)))
4301 goto Bad_Link
; /* disk full error */
4304 /* add the name to the directory */
4305 SetDirHandle(&dir
, parentptr
);
4306 if ((errorCode
= afs_dir_Create(&dir
, Name
, ExistingFid
)))
4310 /* update the status in the parent vnode */
4311 /**WARNING** --> disk.author SHOULDN'T be modified???? */
4312 Update_ParentVnodeStatus(parentptr
, volptr
, &dir
, client
->z
.ViceId
,
4313 parentptr
->disk
.linkCount
,
4314 client
->z
.InSameNetwork
);
4316 targetptr
->disk
.linkCount
++;
4317 targetptr
->disk
.author
= client
->z
.ViceId
;
4318 targetptr
->changed_newTime
= 1; /* Status change of linked-to file */
4320 /* set up return status */
4321 GetStatus(targetptr
, OutFidStatus
, rights
, anyrights
, parentptr
);
4322 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, 0);
4324 /* convert the write locks to read locks before breaking callbacks */
4325 VVnodeWriteToRead(&errorCode
, targetptr
);
4326 assert_vnode_success_or_salvaging(errorCode
);
4327 VVnodeWriteToRead(&errorCode
, parentptr
);
4328 assert_vnode_success_or_salvaging(errorCode
);
4330 /* break call back on DirFid */
4331 BreakCallBack(client
->z
.host
, DirFid
, 0);
4333 * We also need to break the callback for the file that is hard-linked since part
4334 * of its status (like linkcount) is changed
4336 BreakCallBack(client
->z
.host
, ExistingFid
, 0);
4339 /* Write the all modified vnodes (parent, new files) and volume back */
4340 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
4343 ViceLog(2, ("SAFS_Link returns %d\n", errorCode
));
4350 SRXAFS_Link(struct rx_call
* acall
, struct AFSFid
* DirFid
, char *Name
,
4351 struct AFSFid
* ExistingFid
, struct AFSFetchStatus
* OutFidStatus
,
4352 struct AFSFetchStatus
* OutDirStatus
, struct AFSVolSync
* Sync
)
4355 struct rx_connection
*tcon
;
4357 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4358 struct fsstats fsstats
;
4360 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_LINK
);
4362 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
4366 SAFSS_Link(acall
, DirFid
, Name
, ExistingFid
, OutFidStatus
,
4367 OutDirStatus
, Sync
);
4370 code
= CallPostamble(tcon
, code
, thost
);
4372 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4374 fsstats_FinishOp(&fsstats
, code
);
4376 osi_auditU(acall
, LinkEvent
, code
,
4377 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4378 AUD_FID
, DirFid
, AUD_STR
, Name
,
4379 AUD_FID
, ExistingFid
, AUD_END
);
4386 * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4387 * merged into it when possible.
4390 SAFSS_MakeDir(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
4391 struct AFSStoreStatus
*InStatus
, struct AFSFid
*OutFid
,
4392 struct AFSFetchStatus
*OutFidStatus
,
4393 struct AFSFetchStatus
*OutDirStatus
,
4394 struct AFSCallBack
*CallBack
, struct AFSVolSync
*Sync
)
4396 Vnode
*parentptr
= 0; /* vnode of input Directory */
4397 Vnode
*targetptr
= 0; /* vnode of the new file */
4398 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4399 Volume
*volptr
= 0; /* pointer to the volume header */
4400 Error errorCode
= 0; /* error code */
4401 struct acl_accessList
*newACL
; /* Access list */
4402 int newACLSize
; /* Size of access list */
4403 DirHandle dir
; /* Handle for dir package I/O */
4404 DirHandle parentdir
; /* Handle for dir package I/O */
4405 struct client
*client
= 0; /* pointer to client structure */
4406 afs_int32 rights
, anyrights
; /* rights for this and any user */
4407 struct client
*t_client
; /* tmp ptr to client data */
4408 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4409 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4412 FidZero(&parentdir
);
4414 /* Get ptr to client data for user Id for logging */
4415 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4416 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4418 ("SAFS_MakeDir %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name
,
4419 DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
4420 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4422 AFSCallStats
.MakeDir
++, AFSCallStats
.TotalCalls
++;
4424 if (!FileNameOK(Name
)) {
4430 * Get the vnode and volume for the parent dir along with the caller's
4434 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
4435 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4436 &rights
, &anyrights
))) {
4440 /* set volume synchronization information */
4441 SetVolumeSync(Sync
, volptr
);
4443 /* Write access to the parent directory? */
4444 #ifdef DIRCREATE_NEED_WRITE
4446 * requires w access for the user to create a directory. this
4447 * closes a loophole in the current security arrangement, since a
4448 * user with i access only can create a directory and get the
4449 * implcit a access that goes with dir ownership, and proceed to
4450 * subvert quota in the volume.
4452 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_INSERT
))
4453 || (errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_WRITE
))) {
4455 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_INSERT
))) {
4456 #endif /* DIRCREATE_NEED_WRITE */
4459 #define EMPTYDIRBLOCKS 2
4460 /* get a new vnode and set it up */
4462 Alloc_NewVnode(parentptr
, &parentdir
, volptr
, &targetptr
, Name
,
4463 OutFid
, vDirectory
, EMPTYDIRBLOCKS
))) {
4467 /* Update the status for the parent dir */
4468 Update_ParentVnodeStatus(parentptr
, volptr
, &parentdir
, client
->z
.ViceId
,
4469 parentptr
->disk
.linkCount
+ 1,
4470 client
->z
.InSameNetwork
);
4472 /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4473 opr_Verify((SetAccessList(&targetptr
, &volptr
, &newACL
, &newACLSize
,
4474 &parentwhentargetnotdir
, NULL
, 0)) == 0);
4475 opr_Assert(parentwhentargetnotdir
== 0);
4476 memcpy((char *)newACL
, (char *)VVnodeACL(parentptr
), VAclSize(parentptr
));
4478 /* update the status for the target vnode */
4479 Update_TargetVnodeStatus(targetptr
, TVS_MKDIR
, client
, InStatus
,
4480 parentptr
, volptr
, 0, 0);
4482 /* Actually create the New directory in the directory package */
4483 SetDirHandle(&dir
, targetptr
);
4484 opr_Verify(!(afs_dir_MakeDir(&dir
, (afs_int32
*)OutFid
,
4485 (afs_int32
*)DirFid
)));
4487 VN_SET_LEN(targetptr
, (afs_fsize_t
) afs_dir_Length(&dir
));
4489 /* set up return status */
4490 GetStatus(targetptr
, OutFidStatus
, rights
, anyrights
, parentptr
);
4491 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, NULL
);
4493 /* convert the write lock to a read lock before breaking callbacks */
4494 VVnodeWriteToRead(&errorCode
, parentptr
);
4495 assert_vnode_success_or_salvaging(errorCode
);
4497 /* break call back on DirFid */
4498 BreakCallBack(client
->z
.host
, DirFid
, 0);
4500 /* Return a callback promise to caller */
4501 SetCallBackStruct(AddCallBack(client
->z
.host
, OutFid
), CallBack
);
4504 /* Write the all modified vnodes (parent, new files) and volume back */
4505 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
4509 ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode
));
4512 } /*SAFSS_MakeDir */
4516 SRXAFS_MakeDir(struct rx_call
* acall
, struct AFSFid
* DirFid
, char *Name
,
4517 struct AFSStoreStatus
* InStatus
, struct AFSFid
* OutFid
,
4518 struct AFSFetchStatus
* OutFidStatus
,
4519 struct AFSFetchStatus
* OutDirStatus
,
4520 struct AFSCallBack
* CallBack
, struct AFSVolSync
* Sync
)
4523 struct rx_connection
*tcon
;
4525 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4526 struct fsstats fsstats
;
4528 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_MAKEDIR
);
4530 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
4534 SAFSS_MakeDir(acall
, DirFid
, Name
, InStatus
, OutFid
, OutFidStatus
,
4535 OutDirStatus
, CallBack
, Sync
);
4538 code
= CallPostamble(tcon
, code
, thost
);
4540 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4542 fsstats_FinishOp(&fsstats
, code
);
4544 osi_auditU(acall
, MakeDirEvent
, code
,
4545 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4546 AUD_FID
, DirFid
, AUD_STR
, Name
,
4547 AUD_FID
, OutFid
, AUD_END
);
4550 } /*SRXAFS_MakeDir */
4554 * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4555 * merged into it when possible.
4558 SAFSS_RemoveDir(struct rx_call
*acall
, struct AFSFid
*DirFid
, char *Name
,
4559 struct AFSFetchStatus
*OutDirStatus
, struct AFSVolSync
*Sync
)
4561 Vnode
*parentptr
= 0; /* vnode of input Directory */
4562 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4563 Vnode
*targetptr
= 0; /* file to be deleted */
4564 AFSFid fileFid
; /* area for Fid from the directory */
4565 Error errorCode
= 0; /* error code */
4566 DirHandle dir
; /* Handle for dir package I/O */
4567 Volume
*volptr
= 0; /* pointer to the volume header */
4568 struct client
*client
= 0; /* pointer to client structure */
4569 afs_int32 rights
, anyrights
; /* rights for this and any user */
4570 struct client
*t_client
; /* tmp ptr to client data */
4571 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4572 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4576 /* Get ptr to client data for user Id for logging */
4577 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4578 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4580 ("SAFS_RemoveDir %s, Did = %u.%u.%u, Host %s:%d, Id %d\n", Name
,
4581 DirFid
->Volume
, DirFid
->Vnode
, DirFid
->Unique
,
4582 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4584 AFSCallStats
.RemoveDir
++, AFSCallStats
.TotalCalls
++;
4587 * Get the vnode and volume for the parent dir along with the caller's
4591 GetVolumePackage(acall
, DirFid
, &volptr
, &parentptr
, MustBeDIR
,
4592 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4593 &rights
, &anyrights
))) {
4597 /* set volume synchronization information */
4598 SetVolumeSync(Sync
, volptr
);
4600 /* Does the caller has delete (&write) access to the parent dir? */
4601 if ((errorCode
= CheckWriteMode(parentptr
, rights
, PRSFS_DELETE
))) {
4605 /* Do the actual delete of the desired (empty) directory, Name */
4607 DeleteTarget(parentptr
, volptr
, &targetptr
, &dir
, &fileFid
, Name
,
4612 /* Update the status for the parent dir; link count is also adjusted */
4613 Update_ParentVnodeStatus(parentptr
, volptr
, &dir
, client
->z
.ViceId
,
4614 parentptr
->disk
.linkCount
- 1,
4615 client
->z
.InSameNetwork
);
4617 /* Return to the caller the updated parent dir status */
4618 GetStatus(parentptr
, OutDirStatus
, rights
, anyrights
, NULL
);
4621 * Note: it is not necessary to break the callback on fileFid, since
4622 * refcount is now 0, so no one should be able to refer to the dir
4625 DeleteFileCallBacks(&fileFid
);
4627 /* convert the write lock to a read lock before breaking callbacks */
4628 VVnodeWriteToRead(&errorCode
, parentptr
);
4629 assert_vnode_success_or_salvaging(errorCode
);
4631 /* break call back on DirFid and fileFid */
4632 BreakCallBack(client
->z
.host
, DirFid
, 0);
4635 /* Write the all modified vnodes (parent, new files) and volume back */
4636 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, parentptr
,
4639 ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode
));
4642 } /*SAFSS_RemoveDir */
4646 SRXAFS_RemoveDir(struct rx_call
* acall
, struct AFSFid
* DirFid
, char *Name
,
4647 struct AFSFetchStatus
* OutDirStatus
,
4648 struct AFSVolSync
* Sync
)
4651 struct rx_connection
*tcon
;
4653 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4654 struct fsstats fsstats
;
4656 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_REMOVEDIR
);
4658 if ((code
= CallPreamble(acall
, ACTIVECALL
, DirFid
, &tcon
, &thost
)))
4661 code
= SAFSS_RemoveDir(acall
, DirFid
, Name
, OutDirStatus
, Sync
);
4664 code
= CallPostamble(tcon
, code
, thost
);
4666 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4668 fsstats_FinishOp(&fsstats
, code
);
4670 osi_auditU(acall
, RemoveDirEvent
, code
,
4671 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4672 AUD_FID
, DirFid
, AUD_STR
, Name
, AUD_END
);
4675 } /*SRXAFS_RemoveDir */
4679 * This routine is called exclusively by SRXAFS_SetLock(), and should be
4680 * merged into it when possible.
4683 SAFSS_SetLock(struct rx_call
*acall
, struct AFSFid
*Fid
, ViceLockType type
,
4684 struct AFSVolSync
*Sync
)
4686 Vnode
*targetptr
= 0; /* vnode of input file */
4687 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4688 Error errorCode
= 0; /* error code */
4689 Volume
*volptr
= 0; /* pointer to the volume header */
4690 struct client
*client
= 0; /* pointer to client structure */
4691 afs_int32 rights
, anyrights
; /* rights for this and any user */
4692 struct client
*t_client
; /* tmp ptr to client data */
4693 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4694 static char *locktype
[4] = { "LockRead", "LockWrite", "LockExtend", "LockRelease" };
4695 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4697 if (type
!= LockRead
&& type
!= LockWrite
) {
4701 /* Get ptr to client data for user Id for logging */
4702 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4703 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4705 ("SAFS_SetLock type = %s Fid = %u.%u.%u, Host %s:%d, Id %d\n",
4706 locktype
[(int)type
], Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
,
4707 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4709 AFSCallStats
.SetLock
++, AFSCallStats
.TotalCalls
++;
4712 * Get the vnode and volume for the desired file along with the caller's
4716 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
4717 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4718 &rights
, &anyrights
))) {
4722 /* set volume synchronization information */
4723 SetVolumeSync(Sync
, volptr
);
4725 /* Handle the particular type of set locking, type */
4726 errorCode
= HandleLocking(targetptr
, client
, rights
, type
);
4729 /* Write the all modified vnodes (parent, new files) and volume back */
4730 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
4731 (Vnode
*) 0, volptr
, &client
);
4733 if ((errorCode
== VREADONLY
) && (type
== LockRead
))
4734 errorCode
= 0; /* allow read locks on RO volumes without saving state */
4736 ViceLog(2, ("SAFS_SetLock returns %d\n", errorCode
));
4739 } /*SAFSS_SetLock */
4743 SRXAFS_OldSetLock(struct rx_call
* acall
, struct AFSFid
* Fid
,
4744 ViceLockType type
, struct AFSVolSync
* Sync
)
4746 return SRXAFS_SetLock(acall
, Fid
, type
, Sync
);
4747 } /*SRXAFS_OldSetLock */
4751 SRXAFS_SetLock(struct rx_call
* acall
, struct AFSFid
* Fid
, ViceLockType type
,
4752 struct AFSVolSync
* Sync
)
4755 struct rx_connection
*tcon
;
4757 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4758 struct fsstats fsstats
;
4760 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_SETLOCK
);
4762 if ((code
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
4765 code
= SAFSS_SetLock(acall
, Fid
, type
, Sync
);
4768 code
= CallPostamble(tcon
, code
, thost
);
4770 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4772 fsstats_FinishOp(&fsstats
, code
);
4774 osi_auditU(acall
, SetLockEvent
, code
,
4775 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4776 AUD_FID
, Fid
, AUD_LONG
, type
, AUD_END
);
4778 } /*SRXAFS_SetLock */
4782 * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
4783 * merged into it when possible.
4786 SAFSS_ExtendLock(struct rx_call
*acall
, struct AFSFid
*Fid
,
4787 struct AFSVolSync
*Sync
)
4789 Vnode
*targetptr
= 0; /* vnode of input file */
4790 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4791 Error errorCode
= 0; /* error code */
4792 Volume
*volptr
= 0; /* pointer to the volume header */
4793 struct client
*client
= 0; /* pointer to client structure */
4794 afs_int32 rights
, anyrights
; /* rights for this and any user */
4795 struct client
*t_client
; /* tmp ptr to client data */
4796 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4797 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4799 /* Get ptr to client data for user Id for logging */
4800 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4801 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4803 ("SAFS_ExtendLock Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid
->Volume
,
4804 Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
4805 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4807 AFSCallStats
.ExtendLock
++, AFSCallStats
.TotalCalls
++;
4810 * Get the vnode and volume for the desired file along with the caller's
4814 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
4815 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4816 &rights
, &anyrights
))) {
4817 goto Bad_ExtendLock
;
4820 /* set volume synchronization information */
4821 SetVolumeSync(Sync
, volptr
);
4823 /* Handle the actual lock extension */
4824 errorCode
= HandleLocking(targetptr
, client
, rights
, LockExtend
);
4827 /* Put back file's vnode and volume */
4828 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
4829 (Vnode
*) 0, volptr
, &client
);
4831 if (errorCode
== VREADONLY
) /* presumably, we already granted this lock */
4832 errorCode
= 0; /* under our generous policy re RO vols */
4834 ViceLog(2, ("SAFS_ExtendLock returns %d\n", errorCode
));
4837 } /*SAFSS_ExtendLock */
4841 SRXAFS_OldExtendLock(struct rx_call
* acall
, struct AFSFid
* Fid
,
4842 struct AFSVolSync
* Sync
)
4844 return SRXAFS_ExtendLock(acall
, Fid
, Sync
);
4845 } /*SRXAFS_OldExtendLock */
4849 SRXAFS_ExtendLock(struct rx_call
* acall
, struct AFSFid
* Fid
,
4850 struct AFSVolSync
* Sync
)
4853 struct rx_connection
*tcon
;
4855 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4856 struct fsstats fsstats
;
4858 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_EXTENDLOCK
);
4860 if ((code
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
4861 goto Bad_ExtendLock
;
4863 code
= SAFSS_ExtendLock(acall
, Fid
, Sync
);
4866 code
= CallPostamble(tcon
, code
, thost
);
4868 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4870 fsstats_FinishOp(&fsstats
, code
);
4872 osi_auditU(acall
, ExtendLockEvent
, code
,
4873 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4874 AUD_FID
, Fid
, AUD_END
);
4877 } /*SRXAFS_ExtendLock */
4881 * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
4882 * merged into it when possible.
4885 SAFSS_ReleaseLock(struct rx_call
*acall
, struct AFSFid
*Fid
,
4886 struct AFSVolSync
*Sync
)
4888 Vnode
*targetptr
= 0; /* vnode of input file */
4889 Vnode
*parentwhentargetnotdir
= 0; /* parent for use in SetAccessList */
4890 Error errorCode
= 0; /* error code */
4891 Volume
*volptr
= 0; /* pointer to the volume header */
4892 struct client
*client
= 0; /* pointer to client structure */
4893 afs_int32 rights
, anyrights
; /* rights for this and any user */
4894 struct client
*t_client
; /* tmp ptr to client data */
4895 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
4896 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
4898 /* Get ptr to client data for user Id for logging */
4899 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4900 logHostAddr
.s_addr
= rxr_HostOf(tcon
);
4902 ("SAFS_ReleaseLock Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid
->Volume
,
4903 Fid
->Vnode
, Fid
->Unique
, inet_ntoa(logHostAddr
),
4904 ntohs(rxr_PortOf(tcon
)), t_client
->z
.ViceId
));
4906 AFSCallStats
.ReleaseLock
++, AFSCallStats
.TotalCalls
++;
4909 * Get the vnode and volume for the desired file along with the caller's
4913 GetVolumePackage(acall
, Fid
, &volptr
, &targetptr
, DONTCHECK
,
4914 &parentwhentargetnotdir
, &client
, WRITE_LOCK
,
4915 &rights
, &anyrights
))) {
4916 goto Bad_ReleaseLock
;
4919 /* set volume synchronization information */
4920 SetVolumeSync(Sync
, volptr
);
4922 /* Handle the actual lock release */
4923 if ((errorCode
= HandleLocking(targetptr
, client
, rights
, LockRelease
)))
4924 goto Bad_ReleaseLock
;
4926 /* if no more locks left, a callback would be triggered here */
4927 if (targetptr
->disk
.lock
.lockCount
<= 0) {
4928 /* convert the write lock to a read lock before breaking callbacks */
4929 VVnodeWriteToRead(&errorCode
, targetptr
);
4930 assert_vnode_success_or_salvaging(errorCode
);
4931 BreakCallBack(client
->z
.host
, Fid
, 0);
4935 /* Put back file's vnode and volume */
4936 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
4937 (Vnode
*) 0, volptr
, &client
);
4939 if (errorCode
== VREADONLY
) /* presumably, we already granted this lock */
4940 errorCode
= 0; /* under our generous policy re RO vols */
4942 ViceLog(2, ("SAFS_ReleaseLock returns %d\n", errorCode
));
4945 } /*SAFSS_ReleaseLock */
4949 SRXAFS_OldReleaseLock(struct rx_call
* acall
, struct AFSFid
* Fid
,
4950 struct AFSVolSync
* Sync
)
4952 return SRXAFS_ReleaseLock(acall
, Fid
, Sync
);
4953 } /*SRXAFS_OldReleaseLock */
4957 SRXAFS_ReleaseLock(struct rx_call
* acall
, struct AFSFid
* Fid
,
4958 struct AFSVolSync
* Sync
)
4961 struct rx_connection
*tcon
;
4963 struct client
*t_client
= NULL
; /* tmp ptr to client data */
4964 struct fsstats fsstats
;
4966 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_RELEASELOCK
);
4968 if ((code
= CallPreamble(acall
, ACTIVECALL
, Fid
, &tcon
, &thost
)))
4969 goto Bad_ReleaseLock
;
4971 code
= SAFSS_ReleaseLock(acall
, Fid
, Sync
);
4974 code
= CallPostamble(tcon
, code
, thost
);
4976 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
4978 fsstats_FinishOp(&fsstats
, code
);
4980 osi_auditU(acall
, ReleaseLockEvent
, code
,
4981 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
4982 AUD_FID
, Fid
, AUD_END
);
4985 } /*SRXAFS_ReleaseLock */
4989 SetSystemStats(struct AFSStatistics
*stats
)
4991 /* Fix this sometime soon.. */
4992 /* Because hey, it's not like we have a network monitoring protocol... */
4994 stats
->CurrentTime
= time(NULL
);
4995 } /*SetSystemStats */
4998 SetAFSStats(struct AFSStatistics
*stats
)
5000 extern afs_int32 StartTime
, CurrentConnections
;
5004 stats
->CurrentMsgNumber
= 0;
5005 stats
->OldestMsgNumber
= 0;
5006 stats
->StartTime
= StartTime
;
5007 stats
->CurrentConnections
= CurrentConnections
;
5008 stats
->TotalAFSCalls
= AFSCallStats
.TotalCalls
;
5009 stats
->TotalFetchs
=
5010 AFSCallStats
.FetchData
+ AFSCallStats
.FetchACL
+
5011 AFSCallStats
.FetchStatus
;
5012 stats
->FetchDatas
= AFSCallStats
.FetchData
;
5013 stats
->FetchedBytes
= AFSCallStats
.TotalFetchedBytes
;
5014 seconds
= AFSCallStats
.AccumFetchTime
/ 1000;
5017 stats
->FetchDataRate
= AFSCallStats
.TotalFetchedBytes
/ seconds
;
5018 stats
->TotalStores
=
5019 AFSCallStats
.StoreData
+ AFSCallStats
.StoreACL
+
5020 AFSCallStats
.StoreStatus
;
5021 stats
->StoreDatas
= AFSCallStats
.StoreData
;
5022 stats
->StoredBytes
= AFSCallStats
.TotalStoredBytes
;
5023 seconds
= AFSCallStats
.AccumStoreTime
/ 1000;
5026 stats
->StoreDataRate
= AFSCallStats
.TotalStoredBytes
/ seconds
;
5027 stats
->ProcessSize
= opr_procsize();
5029 h_GetWorkStats((int *)&(stats
->WorkStations
),
5030 (int *)&(stats
->ActiveWorkStations
), (int *)0,
5031 (afs_int32
) (time(NULL
)) - (15 * 60));
5035 /* Get disk related information from all AFS partitions. */
5038 SetVolumeStats(struct AFSStatistics
*stats
)
5040 struct DiskPartition64
*part
;
5043 for (part
= DiskPartitionList
; part
&& i
< AFS_MSTATDISKS
;
5044 part
= part
->next
) {
5045 stats
->Disks
[i
].TotalBlocks
= RoundInt64ToInt31(part
->totalUsable
);
5046 stats
->Disks
[i
].BlocksAvailable
= RoundInt64ToInt31(part
->free
);
5047 memset(stats
->Disks
[i
].Name
, 0, AFS_DISKNAMESIZE
);
5048 strncpy(stats
->Disks
[i
].Name
, part
->name
, AFS_DISKNAMESIZE
);
5051 while (i
< AFS_MSTATDISKS
) {
5052 stats
->Disks
[i
].TotalBlocks
= -1;
5055 } /*SetVolumeStats */
5058 SRXAFS_GetStatistics(struct rx_call
*acall
, struct ViceStatistics
*Statistics
)
5061 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
5063 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5064 struct fsstats fsstats
;
5066 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETSTATISTICS
);
5068 if ((code
= CallPreamble(acall
, NOTACTIVECALL
, NULL
, &tcon
, &thost
)))
5069 goto Bad_GetStatistics
;
5071 ViceLog(1, ("SAFS_GetStatistics Received\n"));
5073 AFSCallStats
.GetStatistics
++, AFSCallStats
.TotalCalls
++;
5075 memset(Statistics
, 0, sizeof(*Statistics
));
5076 SetAFSStats((struct AFSStatistics
*)Statistics
);
5077 SetVolumeStats((struct AFSStatistics
*)Statistics
);
5078 SetSystemStats((struct AFSStatistics
*)Statistics
);
5081 code
= CallPostamble(tcon
, code
, thost
);
5083 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
5085 fsstats_FinishOp(&fsstats
, code
);
5087 osi_auditU(acall
, GetStatisticsEvent
, code
,
5088 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0, AUD_END
);
5090 } /*SRXAFS_GetStatistics */
5094 SRXAFS_GetStatistics64(struct rx_call
*acall
, afs_int32 statsVersion
, ViceStatistics64
*Statistics
)
5096 extern afs_int32 StartTime
, CurrentConnections
;
5099 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
5101 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5102 struct fsstats fsstats
;
5104 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETSTATISTICS
);
5106 if ((code
= CallPreamble(acall
, NOTACTIVECALL
, NULL
, &tcon
, &thost
)))
5107 goto Bad_GetStatistics64
;
5109 if (statsVersion
!= STATS64_VERSION
) {
5111 goto Bad_GetStatistics64
;
5114 ViceLog(1, ("SAFS_GetStatistics64 Received\n"));
5115 Statistics
->ViceStatistics64_val
=
5116 malloc(statsVersion
*sizeof(afs_uint64
));
5117 Statistics
->ViceStatistics64_len
= statsVersion
;
5119 AFSCallStats
.GetStatistics
++, AFSCallStats
.TotalCalls
++;
5120 Statistics
->ViceStatistics64_val
[STATS64_STARTTIME
] = StartTime
;
5121 Statistics
->ViceStatistics64_val
[STATS64_CURRENTCONNECTIONS
] =
5123 Statistics
->ViceStatistics64_val
[STATS64_TOTALVICECALLS
] =
5124 AFSCallStats
.TotalCalls
;
5125 Statistics
->ViceStatistics64_val
[STATS64_TOTALFETCHES
] =
5126 AFSCallStats
.FetchData
+ AFSCallStats
.FetchACL
+
5127 AFSCallStats
.FetchStatus
;
5128 Statistics
->ViceStatistics64_val
[STATS64_FETCHDATAS
] =
5129 AFSCallStats
.FetchData
;
5130 Statistics
->ViceStatistics64_val
[STATS64_FETCHEDBYTES
] =
5131 AFSCallStats
.TotalFetchedBytes
;
5132 seconds
= AFSCallStats
.AccumFetchTime
/ 1000;
5135 Statistics
->ViceStatistics64_val
[STATS64_FETCHDATARATE
] =
5136 AFSCallStats
.TotalFetchedBytes
/ seconds
;
5137 Statistics
->ViceStatistics64_val
[STATS64_TOTALSTORES
] =
5138 AFSCallStats
.StoreData
+ AFSCallStats
.StoreACL
+
5139 AFSCallStats
.StoreStatus
;
5140 Statistics
->ViceStatistics64_val
[STATS64_STOREDATAS
] =
5141 AFSCallStats
.StoreData
;
5142 Statistics
->ViceStatistics64_val
[STATS64_STOREDBYTES
] =
5143 AFSCallStats
.TotalStoredBytes
;
5144 seconds
= AFSCallStats
.AccumStoreTime
/ 1000;
5147 Statistics
->ViceStatistics64_val
[STATS64_STOREDATARATE
] =
5148 AFSCallStats
.TotalStoredBytes
/ seconds
;
5149 Statistics
->ViceStatistics64_val
[STATS64_PROCESSSIZE
] = opr_procsize();
5151 h_GetWorkStats64(&(Statistics
->ViceStatistics64_val
[STATS64_WORKSTATIONS
]),
5152 &(Statistics
->ViceStatistics64_val
[STATS64_ACTIVEWORKSTATIONS
]),
5154 (afs_int32
) (time(NULL
)) - (15 * 60));
5156 Statistics
->ViceStatistics64_val
[STATS64_CURRENTTIME
] = time(NULL
);
5158 Bad_GetStatistics64
:
5159 code
= CallPostamble(tcon
, code
, thost
);
5161 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
5163 fsstats_FinishOp(&fsstats
, code
);
5165 osi_auditU(acall
, GetStatisticsEvent
, code
,
5166 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0, AUD_END
);
5168 } /*SRXAFS_GetStatistics */
5171 /*------------------------------------------------------------------------
5172 * EXPORTED SRXAFS_XStatsVersion
5175 * Routine called by the server-side RPC interface to implement
5176 * pulling out the xstat version number for the File Server.
5179 * a_versionP : Ptr to the version number variable to set.
5185 * Nothing interesting.
5189 *------------------------------------------------------------------------*/
5192 SRXAFS_XStatsVersion(struct rx_call
* a_call
, afs_int32
* a_versionP
)
5193 { /*SRXAFS_XStatsVersion */
5195 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5196 struct rx_connection
*tcon
= rx_ConnectionOf(a_call
);
5197 struct fsstats fsstats
;
5199 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_XSTATSVERSION
);
5201 *a_versionP
= AFS_XSTAT_VERSION
;
5203 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
5205 fsstats_FinishOp(&fsstats
, 0);
5207 osi_auditU(a_call
, XStatsVersionEvent
, 0,
5208 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0, AUD_END
);
5210 } /*SRXAFS_XStatsVersion */
5213 /*------------------------------------------------------------------------
5214 * PRIVATE FillPerfValues
5217 * Routine called to fill a regular performance data structure.
5220 * a_perfP : Ptr to perf structure to fill
5226 * Various collections need this info, so the guts were put in
5227 * this separate routine.
5231 *------------------------------------------------------------------------*/
5234 FillPerfValues(struct afs_PerfStats
*a_perfP
)
5235 { /*FillPerfValues */
5236 int dir_Buffers
; /*# buffers in use by dir package */
5237 int dir_Calls
; /*# read calls in dir package */
5238 int dir_IOs
; /*# I/O ops in dir package */
5239 struct rx_statistics
*stats
;
5242 * Vnode cache section.
5244 a_perfP
->vcache_L_Entries
= VnodeClassInfo
[vLarge
].cacheSize
;
5245 a_perfP
->vcache_L_Allocs
= VnodeClassInfo
[vLarge
].allocs
;
5246 a_perfP
->vcache_L_Gets
= VnodeClassInfo
[vLarge
].gets
;
5247 a_perfP
->vcache_L_Reads
= VnodeClassInfo
[vLarge
].reads
;
5248 a_perfP
->vcache_L_Writes
= VnodeClassInfo
[vLarge
].writes
;
5249 a_perfP
->vcache_S_Entries
= VnodeClassInfo
[vSmall
].cacheSize
;
5250 a_perfP
->vcache_S_Allocs
= VnodeClassInfo
[vSmall
].allocs
;
5251 a_perfP
->vcache_S_Gets
= VnodeClassInfo
[vSmall
].gets
;
5252 a_perfP
->vcache_S_Reads
= VnodeClassInfo
[vSmall
].reads
;
5253 a_perfP
->vcache_S_Writes
= VnodeClassInfo
[vSmall
].writes
;
5254 a_perfP
->vcache_H_Entries
= VStats
.hdr_cache_size
;
5255 a_perfP
->vcache_H_Gets
= (int)VStats
.hdr_gets
;
5256 a_perfP
->vcache_H_Replacements
= (int)VStats
.hdr_loads
;
5259 * Directory section.
5261 DStat(&dir_Buffers
, &dir_Calls
, &dir_IOs
);
5262 a_perfP
->dir_Buffers
= (afs_int32
) dir_Buffers
;
5263 a_perfP
->dir_Calls
= (afs_int32
) dir_Calls
;
5264 a_perfP
->dir_IOs
= (afs_int32
) dir_IOs
;
5269 stats
= rx_GetStatistics();
5271 a_perfP
->rx_packetRequests
= (afs_int32
) stats
->packetRequests
;
5272 a_perfP
->rx_noPackets_RcvClass
=
5273 (afs_int32
) stats
->receivePktAllocFailures
;
5274 a_perfP
->rx_noPackets_SendClass
=
5275 (afs_int32
) stats
->sendPktAllocFailures
;
5276 a_perfP
->rx_noPackets_SpecialClass
=
5277 (afs_int32
) stats
->specialPktAllocFailures
;
5278 a_perfP
->rx_socketGreedy
= (afs_int32
) stats
->socketGreedy
;
5279 a_perfP
->rx_bogusPacketOnRead
= (afs_int32
) stats
->bogusPacketOnRead
;
5280 a_perfP
->rx_bogusHost
= (afs_int32
) stats
->bogusHost
;
5281 a_perfP
->rx_noPacketOnRead
= (afs_int32
) stats
->noPacketOnRead
;
5282 a_perfP
->rx_noPacketBuffersOnRead
=
5283 (afs_int32
) stats
->noPacketBuffersOnRead
;
5284 a_perfP
->rx_selects
= (afs_int32
) stats
->selects
;
5285 a_perfP
->rx_sendSelects
= (afs_int32
) stats
->sendSelects
;
5286 a_perfP
->rx_packetsRead_RcvClass
=
5287 (afs_int32
) stats
->packetsRead
[RX_PACKET_CLASS_RECEIVE
];
5288 a_perfP
->rx_packetsRead_SendClass
=
5289 (afs_int32
) stats
->packetsRead
[RX_PACKET_CLASS_SEND
];
5290 a_perfP
->rx_packetsRead_SpecialClass
=
5291 (afs_int32
) stats
->packetsRead
[RX_PACKET_CLASS_SPECIAL
];
5292 a_perfP
->rx_dataPacketsRead
= (afs_int32
) stats
->dataPacketsRead
;
5293 a_perfP
->rx_ackPacketsRead
= (afs_int32
) stats
->ackPacketsRead
;
5294 a_perfP
->rx_dupPacketsRead
= (afs_int32
) stats
->dupPacketsRead
;
5295 a_perfP
->rx_spuriousPacketsRead
=
5296 (afs_int32
) stats
->spuriousPacketsRead
;
5297 a_perfP
->rx_packetsSent_RcvClass
=
5298 (afs_int32
) stats
->packetsSent
[RX_PACKET_CLASS_RECEIVE
];
5299 a_perfP
->rx_packetsSent_SendClass
=
5300 (afs_int32
) stats
->packetsSent
[RX_PACKET_CLASS_SEND
];
5301 a_perfP
->rx_packetsSent_SpecialClass
=
5302 (afs_int32
) stats
->packetsSent
[RX_PACKET_CLASS_SPECIAL
];
5303 a_perfP
->rx_ackPacketsSent
= (afs_int32
) stats
->ackPacketsSent
;
5304 a_perfP
->rx_pingPacketsSent
= (afs_int32
) stats
->pingPacketsSent
;
5305 a_perfP
->rx_abortPacketsSent
= (afs_int32
) stats
->abortPacketsSent
;
5306 a_perfP
->rx_busyPacketsSent
= (afs_int32
) stats
->busyPacketsSent
;
5307 a_perfP
->rx_dataPacketsSent
= (afs_int32
) stats
->dataPacketsSent
;
5308 a_perfP
->rx_dataPacketsReSent
= (afs_int32
) stats
->dataPacketsReSent
;
5309 a_perfP
->rx_dataPacketsPushed
= (afs_int32
) stats
->dataPacketsPushed
;
5310 a_perfP
->rx_ignoreAckedPacket
= (afs_int32
) stats
->ignoreAckedPacket
;
5311 a_perfP
->rx_totalRtt_Sec
= (afs_int32
) stats
->totalRtt
.sec
;
5312 a_perfP
->rx_totalRtt_Usec
= (afs_int32
) stats
->totalRtt
.usec
;
5313 a_perfP
->rx_minRtt_Sec
= (afs_int32
) stats
->minRtt
.sec
;
5314 a_perfP
->rx_minRtt_Usec
= (afs_int32
) stats
->minRtt
.usec
;
5315 a_perfP
->rx_maxRtt_Sec
= (afs_int32
) stats
->maxRtt
.sec
;
5316 a_perfP
->rx_maxRtt_Usec
= (afs_int32
) stats
->maxRtt
.usec
;
5317 a_perfP
->rx_nRttSamples
= (afs_int32
) stats
->nRttSamples
;
5318 a_perfP
->rx_nServerConns
= (afs_int32
) stats
->nServerConns
;
5319 a_perfP
->rx_nClientConns
= (afs_int32
) stats
->nClientConns
;
5320 a_perfP
->rx_nPeerStructs
= (afs_int32
) stats
->nPeerStructs
;
5321 a_perfP
->rx_nCallStructs
= (afs_int32
) stats
->nCallStructs
;
5322 a_perfP
->rx_nFreeCallStructs
= (afs_int32
) stats
->nFreeCallStructs
;
5324 a_perfP
->host_NumHostEntries
= HTs
;
5325 a_perfP
->host_HostBlocks
= HTBlocks
;
5326 h_GetHostNetStats(&(a_perfP
->host_NonDeletedHosts
),
5327 &(a_perfP
->host_HostsInSameNetOrSubnet
),
5328 &(a_perfP
->host_HostsInDiffSubnet
),
5329 &(a_perfP
->host_HostsInDiffNetwork
));
5330 a_perfP
->host_NumClients
= CEs
;
5331 a_perfP
->host_ClientBlocks
= CEBlocks
;
5333 a_perfP
->sysname_ID
= afs_perfstats
.sysname_ID
;
5334 a_perfP
->rx_nBusies
= (afs_int32
) stats
->nBusies
;
5335 a_perfP
->fs_nBusies
= afs_perfstats
.fs_nBusies
;
5336 rx_FreeStatistics(&stats
);
5337 } /*FillPerfValues */
5340 /*------------------------------------------------------------------------
5341 * EXPORTED SRXAFS_GetXStats
5344 * Routine called by the server-side callback RPC interface to
5345 * implement getting the given data collection from the extended
5346 * File Server statistics.
5349 * a_call : Ptr to Rx call on which this request came in.
5350 * a_clientVersionNum : Client version number.
5351 * a_opCode : Desired operation.
5352 * a_serverVersionNumP : Ptr to version number to set.
5353 * a_timeP : Ptr to time value (seconds) to set.
5354 * a_dataP : Ptr to variable array structure to return
5361 * Nothing interesting.
5365 *------------------------------------------------------------------------*/
5368 SRXAFS_GetXStats(struct rx_call
*a_call
, afs_int32 a_clientVersionNum
,
5369 afs_int32 a_collectionNumber
, afs_int32
* a_srvVersionNumP
,
5370 afs_int32
* a_timeP
, AFS_CollData
* a_dataP
)
5371 { /*SRXAFS_GetXStats */
5373 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5374 struct rx_connection
*tcon
= rx_ConnectionOf(a_call
);
5375 int code
; /*Return value */
5376 afs_int32
*dataBuffP
; /*Ptr to data to be returned */
5377 afs_int32 dataBytes
; /*Bytes in data buffer */
5378 struct fsstats fsstats
;
5380 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETXSTATS
);
5382 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
5384 * Record the time of day and the server version number.
5386 *a_srvVersionNumP
= AFS_XSTAT_VERSION
;
5387 *a_timeP
= (afs_int32
) time(NULL
);
5390 * Stuff the appropriate data in there (assume victory)
5394 osi_auditU(a_call
, GetXStatsEvent
,
5395 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
5396 AUD_INT
, a_clientVersionNum
,
5397 AUD_INT
, a_collectionNumber
, AUD_END
);
5401 * We're not keeping stats, so just return successfully with
5404 a_dataP
->AFS_CollData_len
= 0;
5405 a_dataP
->AFS_CollData_val
= NULL
;
5408 switch (a_collectionNumber
) {
5409 case AFS_XSTATSCOLL_CALL_INFO
:
5411 * Pass back all the call-count-related data.
5413 * >>> We are forced to allocate a separate area in which to
5414 * >>> put this stuff in by the RPC stub generator, since it
5415 * >>> will be freed at the tail end of the server stub code.
5419 * I don't think call-level stats are being collected yet
5420 * for the File Server.
5422 dataBytes
= sizeof(struct afs_Stats
);
5423 dataBuffP
= malloc(dataBytes
);
5424 memcpy(dataBuffP
, &afs_cmstats
, dataBytes
);
5425 a_dataP
->AFS_CollData_len
= dataBytes
>> 2;
5426 a_dataP
->AFS_CollData_val
= dataBuffP
;
5428 a_dataP
->AFS_CollData_len
= 0;
5429 a_dataP
->AFS_CollData_val
= NULL
;
5433 case AFS_XSTATSCOLL_PERF_INFO
:
5435 * Pass back all the regular performance-related data.
5437 * >>> We are forced to allocate a separate area in which to
5438 * >>> put this stuff in by the RPC stub generator, since it
5439 * >>> will be freed at the tail end of the server stub code.
5442 afs_perfstats
.numPerfCalls
++;
5443 FillPerfValues(&afs_perfstats
);
5446 * Don't overwrite the spares at the end.
5449 dataBytes
= sizeof(struct afs_PerfStats
);
5450 dataBuffP
= malloc(dataBytes
);
5451 memcpy(dataBuffP
, &afs_perfstats
, dataBytes
);
5452 a_dataP
->AFS_CollData_len
= dataBytes
>> 2;
5453 a_dataP
->AFS_CollData_val
= dataBuffP
;
5456 case AFS_XSTATSCOLL_FULL_PERF_INFO
:
5458 * Pass back the full collection of performance-related data.
5459 * We have to stuff the basic, overall numbers in, but the
5460 * detailed numbers are kept in the structure already.
5462 * >>> We are forced to allocate a separate area in which to
5463 * >>> put this stuff in by the RPC stub generator, since it
5464 * >>> will be freed at the tail end of the server stub code.
5467 afs_perfstats
.numPerfCalls
++;
5468 afs_FullPerfStats
.overall
.numPerfCalls
= afs_perfstats
.numPerfCalls
;
5469 FillPerfValues(&afs_FullPerfStats
.overall
);
5472 * Don't overwrite the spares at the end.
5475 dataBytes
= sizeof(struct fs_stats_FullPerfStats
);
5476 dataBuffP
= malloc(dataBytes
);
5477 memcpy(dataBuffP
, &afs_FullPerfStats
, dataBytes
);
5478 a_dataP
->AFS_CollData_len
= dataBytes
>> 2;
5479 a_dataP
->AFS_CollData_val
= dataBuffP
;
5482 case AFS_XSTATSCOLL_CBSTATS
:
5483 afs_perfstats
.numPerfCalls
++;
5485 dataBytes
= sizeof(struct cbcounters
);
5486 dataBuffP
= malloc(dataBytes
);
5488 extern struct cbcounters cbstuff
;
5489 dataBuffP
[0]=cbstuff
.DeleteFiles
;
5490 dataBuffP
[1]=cbstuff
.DeleteCallBacks
;
5491 dataBuffP
[2]=cbstuff
.BreakCallBacks
;
5492 dataBuffP
[3]=cbstuff
.AddCallBacks
;
5493 dataBuffP
[4]=cbstuff
.GotSomeSpaces
;
5494 dataBuffP
[5]=cbstuff
.DeleteAllCallBacks
;
5495 dataBuffP
[6]=cbstuff
.nFEs
;
5496 dataBuffP
[7]=cbstuff
.nCBs
;
5497 dataBuffP
[8]=cbstuff
.nblks
;
5498 dataBuffP
[9]=cbstuff
.CBsTimedOut
;
5499 dataBuffP
[10]=cbstuff
.nbreakers
;
5500 dataBuffP
[11]=cbstuff
.GSS1
;
5501 dataBuffP
[12]=cbstuff
.GSS2
;
5502 dataBuffP
[13]=cbstuff
.GSS3
;
5503 dataBuffP
[14]=cbstuff
.GSS4
;
5504 dataBuffP
[15]=cbstuff
.GSS5
;
5507 a_dataP
->AFS_CollData_len
= dataBytes
>> 2;
5508 a_dataP
->AFS_CollData_val
= dataBuffP
;
5514 * Illegal collection number.
5516 a_dataP
->AFS_CollData_len
= 0;
5517 a_dataP
->AFS_CollData_val
= NULL
;
5519 } /*Switch on collection number */
5521 fsstats_FinishOp(&fsstats
, code
);
5525 } /*SRXAFS_GetXStats */
5529 common_GiveUpCallBacks(struct rx_call
*acall
, struct AFSCBFids
*FidArray
,
5530 struct AFSCBs
*CallBackArray
)
5532 afs_int32 errorCode
= 0;
5534 struct client
*client
= 0;
5535 struct rx_connection
*tcon
;
5537 struct fsstats fsstats
;
5539 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GIVEUPCALLBACKS
);
5543 ("SAFS_GiveUpCallBacks (Noffids=%d)\n",
5544 FidArray
->AFSCBFids_len
));
5547 AFSCallStats
.GiveUpCallBacks
++, AFSCallStats
.TotalCalls
++;
5549 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
)))
5550 goto Bad_GiveUpCallBacks
;
5552 if (!FidArray
&& !CallBackArray
) {
5554 ("SAFS_GiveUpAllCallBacks: host=%x\n",
5555 (rx_PeerOf(tcon
) ? rx_HostOf(rx_PeerOf(tcon
)) : 0)));
5556 errorCode
= GetClient(tcon
, &client
);
5559 DeleteAllCallBacks_r(client
->z
.host
, 1);
5564 if (FidArray
->AFSCBFids_len
< CallBackArray
->AFSCBs_len
) {
5566 ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n",
5567 FidArray
->AFSCBFids_len
, CallBackArray
->AFSCBs_len
,
5568 (rx_PeerOf(tcon
) ? rx_HostOf(rx_PeerOf(tcon
)) : 0)));
5570 goto Bad_GiveUpCallBacks
;
5573 errorCode
= GetClient(tcon
, &client
);
5575 for (i
= 0; i
< FidArray
->AFSCBFids_len
; i
++) {
5576 struct AFSFid
*fid
= &(FidArray
->AFSCBFids_val
[i
]);
5577 DeleteCallBack(client
->z
.host
, fid
);
5583 Bad_GiveUpCallBacks
:
5584 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
5586 fsstats_FinishOp(&fsstats
, errorCode
);
5590 } /*common_GiveUpCallBacks */
5594 SRXAFS_GiveUpCallBacks(struct rx_call
* acall
, struct AFSCBFids
* FidArray
,
5595 struct AFSCBs
* CallBackArray
)
5597 return common_GiveUpCallBacks(acall
, FidArray
, CallBackArray
);
5598 } /*SRXAFS_GiveUpCallBacks */
5601 SRXAFS_GiveUpAllCallBacks(struct rx_call
* acall
)
5603 return common_GiveUpCallBacks(acall
, 0, 0);
5604 } /*SRXAFS_GiveUpAllCallBacks */
5608 SRXAFS_NGetVolumeInfo(struct rx_call
* acall
, char *avolid
,
5609 struct AFSVolumeInfo
* avolinfo
)
5611 return (VNOVOL
); /* XXX Obsolete routine XXX */
5613 } /*SRXAFS_NGetVolumeInfo */
5617 * Dummy routine. Should never be called (the cache manager should only
5618 * invoke this interface when communicating with a AFS/DFS Protocol
5622 SRXAFS_Lookup(struct rx_call
* call_p
, struct AFSFid
* afs_dfid_p
,
5623 char *afs_name_p
, struct AFSFid
* afs_fid_p
,
5624 struct AFSFetchStatus
* afs_status_p
,
5625 struct AFSFetchStatus
* afs_dir_status_p
,
5626 struct AFSCallBack
* afs_callback_p
,
5627 struct AFSVolSync
* afs_sync_p
)
5634 SRXAFS_GetCapabilities(struct rx_call
* acall
, Capabilities
* capabilities
)
5637 struct rx_connection
*tcon
;
5639 afs_uint32
*dataBuffP
;
5640 afs_int32 dataBytes
;
5643 AFSCallStats
.GetCapabilities
++, AFSCallStats
.TotalCalls
++;
5644 afs_FullPerfStats
.overall
.fs_nGetCaps
++;
5646 ViceLog(2, ("SAFS_GetCapabilties\n"));
5648 if ((code
= CallPreamble(acall
, NOTACTIVECALL
, NULL
, &tcon
, &thost
)))
5651 dataBytes
= 1 * sizeof(afs_int32
);
5652 dataBuffP
= malloc(dataBytes
);
5653 dataBuffP
[0] = VICED_CAPABILITY_ERRORTRANS
| VICED_CAPABILITY_WRITELOCKACL
;
5654 dataBuffP
[0] |= VICED_CAPABILITY_64BITFILES
;
5656 dataBuffP
[0] |= VICED_CAPABILITY_SANEACLS
;
5658 capabilities
->Capabilities_len
= dataBytes
/ sizeof(afs_int32
);
5659 capabilities
->Capabilities_val
= dataBuffP
;
5662 code
= CallPostamble(tcon
, code
, thost
);
5668 /* client is held, but not locked */
5670 FlushClientCPS(struct client
*client
, void *arock
)
5672 ObtainWriteLock(&client
->lock
);
5674 client
->z
.prfail
= 2; /* Means re-eval client's cps */
5676 if ((client
->z
.ViceId
!= ANONYMOUSID
) && client
->z
.CPS
.prlist_val
) {
5677 free(client
->z
.CPS
.prlist_val
);
5678 client
->z
.CPS
.prlist_val
= NULL
;
5679 client
->z
.CPS
.prlist_len
= 0;
5682 ReleaseWriteLock(&client
->lock
);
5688 SRXAFS_FlushCPS(struct rx_call
* acall
, struct ViceIds
* vids
,
5689 struct IPAddrs
* addrs
, afs_int32 spare1
, afs_int32
* spare2
,
5693 afs_int32 nids
, naddrs
;
5694 afs_int32
*vd
, *addr
;
5695 Error errorCode
= 0; /* return code to caller */
5697 ViceLog(1, ("SRXAFS_FlushCPS\n"));
5699 AFSCallStats
.TotalCalls
++;
5702 if (!viced_SuperUser(acall
)) {
5707 nids
= vids
->ViceIds_len
; /* # of users in here */
5708 naddrs
= addrs
->IPAddrs_len
; /* # of hosts in here */
5709 if (nids
< 0 || naddrs
< 0) {
5714 vd
= vids
->ViceIds_val
;
5715 for (i
= 0; i
< nids
; i
++, vd
++) {
5718 h_EnumerateClients(*vd
, FlushClientCPS
, NULL
);
5721 addr
= addrs
->IPAddrs_val
;
5722 for (i
= 0; i
< naddrs
; i
++, addr
++) {
5724 h_flushhostcps(*addr
, htons(7001));
5728 ViceLog(2, ("SAFS_FlushCPS returns %d\n", errorCode
));
5730 } /*SRXAFS_FlushCPS */
5732 /* worthless hack to let CS keep running ancient software */
5734 afs_vtoi(char *aname
)
5740 while ((tc
= *aname
++)) {
5741 if (tc
> '9' || tc
< '0')
5742 return 0; /* invalid name */
5750 * may get name or #, but must handle all weird cases (recognize readonly
5751 * or backup volumes by name or #
5754 CopyVolumeEntry(char *aname
, struct vldbentry
*ave
,
5755 struct VolumeInfo
*av
)
5758 afs_int32 mask
, whichType
;
5759 afs_uint32
*serverHost
, *typePtr
;
5761 /* figure out what type we want if by name */
5763 if (i
>= 8 && strcmp(aname
+ i
- 7, ".backup") == 0)
5764 whichType
= BACKVOL
;
5765 else if (i
>= 10 && strcmp(aname
+ i
- 9, ".readonly") == 0)
5770 vol
= afs_vtoi(aname
);
5772 vol
= ave
->volumeId
[whichType
];
5775 * Now vol has volume # we're interested in. Next, figure out the type
5776 * of the volume by looking finding it in the vldb entry
5778 if ((ave
->flags
& VLF_RWEXISTS
) && vol
== ave
->volumeId
[RWVOL
]) {
5781 } else if ((ave
->flags
& VLF_ROEXISTS
) && vol
== ave
->volumeId
[ROVOL
]) {
5784 } else if ((ave
->flags
& VLF_BACKEXISTS
) && vol
== ave
->volumeId
[BACKVOL
]) {
5785 mask
= VLSF_RWVOL
; /* backup always is on the same volume as parent */
5786 whichType
= BACKVOL
;
5788 return EINVAL
; /* error: can't find volume in vldb entry */
5790 typePtr
= &av
->Type0
;
5791 serverHost
= &av
->Server0
;
5793 av
->Type
= whichType
;
5794 av
->Type0
= av
->Type1
= av
->Type2
= av
->Type3
= av
->Type4
= 0;
5795 if (ave
->flags
& VLF_RWEXISTS
)
5796 typePtr
[RWVOL
] = ave
->volumeId
[RWVOL
];
5797 if (ave
->flags
& VLF_ROEXISTS
)
5798 typePtr
[ROVOL
] = ave
->volumeId
[ROVOL
];
5799 if (ave
->flags
& VLF_BACKEXISTS
)
5800 typePtr
[BACKVOL
] = ave
->volumeId
[BACKVOL
];
5802 for (i
= 0, j
= 0; i
< ave
->nServers
; i
++) {
5803 if ((ave
->serverFlags
[i
] & mask
) == 0)
5804 continue; /* wrong volume */
5805 serverHost
[j
] = ave
->serverNumber
[i
];
5808 av
->ServerCount
= j
;
5810 serverHost
[j
++] = 0; /* bogus 8, but compat only now */
5815 TryLocalVLServer(char *avolid
, struct VolumeInfo
*avolinfo
)
5817 static struct rx_connection
*vlConn
= 0;
5818 static int down
= 0;
5819 static afs_int32 lastDownTime
= 0;
5820 struct vldbentry tve
;
5821 struct rx_securityClass
*vlSec
;
5825 vlSec
= rxnull_NewClientSecurityObject();
5827 rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec
, 0);
5828 rx_SetConnDeadTime(vlConn
, 15); /* don't wait long */
5830 if (down
&& (time(NULL
) < lastDownTime
+ 180)) {
5831 return 1; /* failure */
5834 code
= VL_GetEntryByNameO(vlConn
, avolid
, &tve
);
5836 down
= 0; /* call worked */
5839 lastDownTime
= time(NULL
); /* last time we tried an RPC */
5845 /* otherwise convert to old format vldb entry */
5846 code
= CopyVolumeEntry(avolid
, &tve
, avolinfo
);
5856 SRXAFS_GetVolumeInfo(struct rx_call
* acall
, char *avolid
,
5857 struct VolumeInfo
* avolinfo
)
5860 struct rx_connection
*tcon
;
5862 struct fsstats fsstats
;
5864 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETVOLUMEINFO
);
5866 if ((code
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
)))
5867 goto Bad_GetVolumeInfo
;
5870 AFSCallStats
.GetVolumeInfo
++, AFSCallStats
.TotalCalls
++;
5872 code
= TryLocalVLServer(avolid
, avolinfo
);
5874 ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
5875 code
, avolinfo
->Vid
, avolinfo
->Type
, avolinfo
->Server0
,
5876 avolinfo
->Server1
, avolinfo
->Server2
, avolinfo
->Server3
));
5877 avolinfo
->Type4
= 0xabcd9999; /* tell us to try new vldb */
5880 code
= CallPostamble(tcon
, code
, thost
);
5882 fsstats_FinishOp(&fsstats
, code
);
5886 } /*SRXAFS_GetVolumeInfo */
5890 SRXAFS_GetVolumeStatus(struct rx_call
* acall
, afs_int32 avolid
,
5891 AFSFetchVolumeStatus
* FetchVolStatus
, char **Name
,
5892 char **OfflineMsg
, char **Motd
)
5894 Vnode
*targetptr
= 0; /* vnode of the new file */
5895 Vnode
*parentwhentargetnotdir
= 0; /* vnode of parent */
5896 Error errorCode
= 0; /* error code */
5897 Volume
*volptr
= 0; /* pointer to the volume header */
5898 struct client
*client
= 0; /* pointer to client entry */
5899 afs_int32 rights
, anyrights
; /* rights for this and any user */
5901 struct rx_connection
*tcon
;
5903 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5904 struct fsstats fsstats
;
5906 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETVOLUMESTATUS
);
5908 ViceLog(1, ("SAFS_GetVolumeStatus for volume %u\n", avolid
));
5909 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
)))
5910 goto Bad_GetVolumeStatus
;
5913 AFSCallStats
.GetVolumeStatus
++, AFSCallStats
.TotalCalls
++;
5917 goto Bad_GetVolumeStatus
;
5919 dummyFid
.Volume
= avolid
, dummyFid
.Vnode
=
5920 (afs_int32
) ROOTVNODE
, dummyFid
.Unique
= 1;
5923 GetVolumePackage(acall
, &dummyFid
, &volptr
, &targetptr
, MustBeDIR
,
5924 &parentwhentargetnotdir
, &client
, READ_LOCK
,
5925 &rights
, &anyrights
)))
5926 goto Bad_GetVolumeStatus
;
5928 (void)RXGetVolumeStatus(FetchVolStatus
, Name
, OfflineMsg
, Motd
, volptr
);
5930 Bad_GetVolumeStatus
:
5931 (void)PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
,
5932 (Vnode
*) 0, volptr
, &client
);
5933 ViceLog(2, ("SAFS_GetVolumeStatus returns %d\n", errorCode
));
5934 /* next is to guarantee out strings exist for stub */
5943 if (*OfflineMsg
== 0) {
5944 *OfflineMsg
= malloc(1);
5947 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
5949 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
5951 fsstats_FinishOp(&fsstats
, errorCode
);
5953 osi_auditU(acall
, GetVolumeStatusEvent
, errorCode
,
5954 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
5955 AUD_LONG
, avolid
, AUD_STR
, *Name
, AUD_END
);
5958 } /*SRXAFS_GetVolumeStatus */
5962 SRXAFS_SetVolumeStatus(struct rx_call
* acall
, afs_int32 avolid
,
5963 AFSStoreVolumeStatus
* StoreVolStatus
, char *Name
,
5964 char *OfflineMsg
, char *Motd
)
5966 Vnode
*targetptr
= 0; /* vnode of the new file */
5967 Vnode
*parentwhentargetnotdir
= 0; /* vnode of parent */
5968 Error errorCode
= 0; /* error code */
5969 Volume
*volptr
= 0; /* pointer to the volume header */
5970 struct client
*client
= 0; /* pointer to client entry */
5971 afs_int32 rights
, anyrights
; /* rights for this and any user */
5973 struct rx_connection
*tcon
= rx_ConnectionOf(acall
);
5975 struct client
*t_client
= NULL
; /* tmp ptr to client data */
5976 struct fsstats fsstats
;
5978 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_SETVOLUMESTATUS
);
5980 ViceLog(1, ("SAFS_SetVolumeStatus for volume %u\n", avolid
));
5981 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
)))
5982 goto Bad_SetVolumeStatus
;
5985 AFSCallStats
.SetVolumeStatus
++, AFSCallStats
.TotalCalls
++;
5989 goto Bad_SetVolumeStatus
;
5991 dummyFid
.Volume
= avolid
, dummyFid
.Vnode
=
5992 (afs_int32
) ROOTVNODE
, dummyFid
.Unique
= 1;
5995 GetVolumePackage(acall
, &dummyFid
, &volptr
, &targetptr
, MustBeDIR
,
5996 &parentwhentargetnotdir
, &client
, READ_LOCK
,
5997 &rights
, &anyrights
)))
5998 goto Bad_SetVolumeStatus
;
6000 if (readonlyServer
) {
6001 errorCode
= VREADONLY
;
6002 goto Bad_SetVolumeStatus
;
6004 if (VanillaUser(client
)) {
6006 goto Bad_SetVolumeStatus
;
6010 RXUpdate_VolumeStatus(volptr
, StoreVolStatus
, Name
, OfflineMsg
, Motd
);
6012 Bad_SetVolumeStatus
:
6013 PutVolumePackage(acall
, parentwhentargetnotdir
, targetptr
, (Vnode
*) 0,
6015 ViceLog(2, ("SAFS_SetVolumeStatus returns %d\n", errorCode
));
6016 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
6018 t_client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
6020 fsstats_FinishOp(&fsstats
, errorCode
);
6022 osi_auditU(acall
, SetVolumeStatusEvent
, errorCode
,
6023 AUD_ID
, t_client
? t_client
->z
.ViceId
: 0,
6024 AUD_LONG
, avolid
, AUD_STR
, Name
, AUD_END
);
6026 } /*SRXAFS_SetVolumeStatus */
6028 #define DEFAULTVOLUME "root.afs"
6031 SRXAFS_GetRootVolume(struct rx_call
* acall
, char **VolumeName
)
6037 struct rx_connection
*tcon
;
6039 Error errorCode
= 0;
6041 struct fsstats fsstats
;
6043 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETROOTVOLUME
);
6045 return FSERR_EOPNOTSUPP
;
6048 if (errorCode
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
))
6049 goto Bad_GetRootVolume
;
6051 AFSCallStats
.GetRootVolume
++, AFSCallStats
.TotalCalls
++;
6054 fd
= afs_open(AFSDIR_SERVER_ROOTVOL_FILEPATH
, O_RDONLY
, 0666);
6056 strcpy(temp
, DEFAULTVOLUME
);
6058 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6059 lockf(fd
, F_LOCK
, 0);
6063 len
= read(fd
, temp
, 256);
6064 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6065 lockf(fd
, F_ULOCK
, 0);
6070 if (temp
[len
- 1] == '\n')
6074 *VolumeName
= temp
; /* freed by rx server-side stub */
6077 errorCode
= CallPostamble(tcon
, errorCode
, thost
);
6079 fsstats_FinishOp(&fsstats
, errorCode
);
6084 } /*SRXAFS_GetRootVolume */
6087 /* still works because a struct CBS is the same as a struct AFSOpaque */
6089 SRXAFS_CheckToken(struct rx_call
* acall
, afs_int32 AfsId
,
6090 struct AFSOpaque
* Token
)
6093 struct rx_connection
*tcon
;
6095 struct fsstats fsstats
;
6097 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_CHECKTOKEN
);
6099 if ((code
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &thost
)))
6100 goto Bad_CheckToken
;
6102 code
= FSERR_ECONNREFUSED
;
6105 code
= CallPostamble(tcon
, code
, thost
);
6107 fsstats_FinishOp(&fsstats
, code
);
6111 } /*SRXAFS_CheckToken */
6114 SRXAFS_GetTime(struct rx_call
* acall
, afs_uint32
* Seconds
,
6115 afs_uint32
* USeconds
)
6118 struct rx_connection
*tcon
;
6121 struct fsstats fsstats
;
6123 fsstats_StartOp(&fsstats
, FS_STATS_RPCIDX_GETTIME
);
6125 if ((code
= CallPreamble(acall
, NOTACTIVECALL
, NULL
, &tcon
, &thost
)))
6129 AFSCallStats
.GetTime
++, AFSCallStats
.TotalCalls
++;
6131 gettimeofday(&tpl
, 0);
6132 *Seconds
= tpl
.tv_sec
;
6133 *USeconds
= tpl
.tv_usec
;
6135 ViceLog(2, ("SAFS_GetTime returns %u, %u\n", *Seconds
, *USeconds
));
6138 code
= CallPostamble(tcon
, code
, thost
);
6140 fsstats_FinishOp(&fsstats
, code
);
6144 } /*SRXAFS_GetTime */
6151 * Implement a client's data fetch using Rx.
6154 * volptr : Ptr to the given volume's info.
6155 * targetptr : Pointer to the vnode involved.
6156 * Call : Ptr to the Rx call involved.
6157 * Pos : Offset within the file.
6158 * Len : Length in bytes to read; this value is bogus!
6159 * a_bytesToFetchP : Set to the number of bytes to be fetched from
6161 * a_bytesFetchedP : Set to the actual number of bytes fetched from
6166 FetchData_RXStyle(Volume
* volptr
, Vnode
* targetptr
,
6167 struct rx_call
* Call
, afs_sfsize_t Pos
,
6168 afs_sfsize_t Len
, afs_int32 Int64Mode
,
6169 afs_sfsize_t
* a_bytesToFetchP
,
6170 afs_sfsize_t
* a_bytesFetchedP
)
6172 struct timeval StartTime
, StopTime
; /* used to calculate file transfer rates */
6177 #else /* HAVE_PIOV */
6178 struct iovec tiov
[RX_MAXIOVECS
];
6180 #endif /* HAVE_PIOV */
6185 * Initialize the byte count arguments.
6187 (*a_bytesToFetchP
) = 0;
6188 (*a_bytesFetchedP
) = 0;
6191 ("FetchData_RXStyle: Pos %llu, Len %llu\n", (afs_uintmax_t
) Pos
,
6192 (afs_uintmax_t
) Len
));
6194 if (!VN_GET_INO(targetptr
)) {
6195 afs_int32 zero
= htonl(0);
6197 * This is used for newly created files; we simply send 0 bytes
6198 * back to make the cache manager happy...
6201 rx_Write(Call
, (char *)&zero
, sizeof(afs_int32
)); /* send 0-length */
6202 rx_Write(Call
, (char *)&zero
, sizeof(afs_int32
)); /* send 0-length */
6205 gettimeofday(&StartTime
, 0);
6206 ihP
= targetptr
->handle
;
6209 VTakeOffline(volptr
);
6210 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6211 afs_printable_VolumeId_lu(volptr
->hashid
)));
6214 optSize
= sendBufSize
;
6215 tlen
= FDH_SIZE(fdP
);
6217 ("FetchData_RXStyle: file size %llu\n", (afs_uintmax_t
) tlen
));
6220 VTakeOffline(volptr
);
6221 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6222 afs_printable_VolumeId_lu(volptr
->hashid
)));
6225 if (CheckLength(volptr
, targetptr
, tlen
)) {
6227 VTakeOffline(volptr
);
6234 if (Pos
+ Len
> tlen
) /* get length we should send */
6235 Len
= ((tlen
- Pos
) < 0) ? 0 : tlen
- Pos
;
6238 afs_int32 high
, low
;
6239 SplitOffsetOrSize(Len
, high
, low
);
6240 opr_Assert(Int64Mode
|| (Len
>= 0 && high
== 0) || Len
< 0);
6243 rx_Write(Call
, (char *)&high
, sizeof(afs_int32
)); /* High order bits */
6246 rx_Write(Call
, (char *)&low
, sizeof(afs_int32
)); /* send length on fetch */
6248 (*a_bytesToFetchP
) = Len
;
6250 tbuffer
= AllocSendBuffer();
6251 #endif /* HAVE_PIOV */
6260 nBytes
= FDH_PREAD(fdP
, tbuffer
, wlen
, Pos
);
6261 if (nBytes
!= wlen
) {
6263 FreeSendBuffer((struct afs_buffer
*)tbuffer
);
6264 VTakeOffline(volptr
);
6265 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6266 afs_printable_VolumeId_lu(volptr
->hashid
)));
6269 nBytes
= rx_Write(Call
, tbuffer
, wlen
);
6270 #else /* HAVE_PIOV */
6271 nBytes
= rx_WritevAlloc(Call
, tiov
, &tnio
, RX_MAXIOVECS
, wlen
);
6277 nBytes
= FDH_PREADV(fdP
, tiov
, tnio
, Pos
);
6278 if (nBytes
!= wlen
) {
6280 VTakeOffline(volptr
);
6281 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6282 afs_printable_VolumeId_lu(volptr
->hashid
)));
6285 nBytes
= rx_Writev(Call
, tiov
, tnio
, wlen
);
6286 #endif /* HAVE_PIOV */
6289 * Bump the number of bytes actually sent by the number from this
6292 (*a_bytesFetchedP
) += nBytes
;
6293 if (nBytes
!= wlen
) {
6297 FreeSendBuffer((struct afs_buffer
*)tbuffer
);
6298 #endif /* HAVE_PIOV */
6299 err
= VIsGoingOffline(volptr
);
6308 FreeSendBuffer((struct afs_buffer
*)tbuffer
);
6309 #endif /* HAVE_PIOV */
6311 gettimeofday(&StopTime
, 0);
6313 /* Adjust all Fetch Data related stats */
6315 if (AFSCallStats
.TotalFetchedBytes
> 2000000000) /* Reset if over 2 billion */
6316 AFSCallStats
.TotalFetchedBytes
= AFSCallStats
.AccumFetchTime
= 0;
6317 AFSCallStats
.AccumFetchTime
+=
6318 ((StopTime
.tv_sec
- StartTime
.tv_sec
) * 1000) +
6319 ((StopTime
.tv_usec
- StartTime
.tv_usec
) / 1000);
6321 afs_fsize_t targLen
;
6322 VN_GET_LEN(targLen
, targetptr
);
6323 AFSCallStats
.TotalFetchedBytes
+= targLen
;
6324 AFSCallStats
.FetchSize1
++;
6325 if (targLen
< SIZE2
)
6326 AFSCallStats
.FetchSize2
++;
6327 else if (targLen
< SIZE3
)
6328 AFSCallStats
.FetchSize3
++;
6329 else if (targLen
< SIZE4
)
6330 AFSCallStats
.FetchSize4
++;
6332 AFSCallStats
.FetchSize5
++;
6337 } /*FetchData_RXStyle */
6340 GetLinkCountAndSize(Volume
* vp
, FdHandle_t
* fdP
, int *lc
,
6341 afs_sfsize_t
* size
)
6343 #ifdef AFS_NAMEI_ENV
6345 lhp
= IH_OPEN(V_linkHandle(vp
));
6348 *lc
= namei_GetLinkCount(lhp
, fdP
->fd_ih
->ih_ino
, 0, 0, 1);
6352 *size
= OS_SIZE(fdP
->fd_fd
);
6353 return (*size
== -1) ? -1 : 0;
6355 struct afs_stat status
;
6357 if (afs_fstat(fdP
->fd_fd
, &status
) < 0) {
6361 *lc
= GetLinkCount(vp
, &status
);
6362 *size
= status
.st_size
;
6371 * Implement a client's data store using Rx.
6374 * volptr : Ptr to the given volume's info.
6375 * targetptr : Pointer to the vnode involved.
6376 * Call : Ptr to the Rx call involved.
6377 * Pos : Offset within the file.
6378 * Len : Length in bytes to store; this value is bogus!
6379 * a_bytesToStoreP : Set to the number of bytes to be stored to
6381 * a_bytesStoredP : Set to the actual number of bytes stored to
6385 StoreData_RXStyle(Volume
* volptr
, Vnode
* targetptr
, struct AFSFid
* Fid
,
6386 struct client
* client
, struct rx_call
* Call
,
6387 afs_fsize_t Pos
, afs_fsize_t Length
, afs_fsize_t FileLength
,
6389 afs_sfsize_t
* a_bytesToStoreP
,
6390 afs_sfsize_t
* a_bytesStoredP
)
6392 afs_sfsize_t bytesTransfered
; /* number of bytes actually transfered */
6393 Error errorCode
= 0; /* Returned error code to caller */
6395 char *tbuffer
; /* data copying buffer */
6396 #else /* HAVE_PIOV */
6397 struct iovec tiov
[RX_MAXIOVECS
]; /* no data copying with iovec */
6398 int tnio
; /* temp for iovec size */
6399 #endif /* HAVE_PIOV */
6400 afs_sfsize_t tlen
; /* temp for xfr length */
6401 Inode tinode
; /* inode for I/O */
6402 afs_int32 optSize
; /* optimal transfer size */
6403 afs_sfsize_t DataLength
= 0; /* size of inode */
6404 afs_sfsize_t TruncatedLength
; /* size after ftruncate */
6405 afs_fsize_t NewLength
; /* size after this store completes */
6406 afs_sfsize_t adjustSize
; /* bytes to call VAdjust... with */
6407 int linkCount
= 0; /* link count on inode */
6410 struct in_addr logHostAddr
; /* host ip holder for inet_ntoa */
6414 * Initialize the byte count arguments.
6416 (*a_bytesToStoreP
) = 0;
6417 (*a_bytesStoredP
) = 0;
6420 * We break the callbacks here so that the following signal will not
6423 BreakCallBack(client
->z
.host
, Fid
, 0);
6425 if (Pos
== -1 || VN_GET_INO(targetptr
) == 0) {
6426 /* the inode should have been created in Alloc_NewVnode */
6427 logHostAddr
.s_addr
= rxr_HostOf(rx_ConnectionOf(Call
));
6429 ("StoreData_RXStyle : Inode non-existent Fid = %u.%u.%u, inode = %llu, Pos %llu Host %s:%d\n",
6430 Fid
->Volume
, Fid
->Vnode
, Fid
->Unique
,
6431 (afs_uintmax_t
) VN_GET_INO(targetptr
), (afs_uintmax_t
) Pos
,
6432 inet_ntoa(logHostAddr
), ntohs(rxr_PortOf(rx_ConnectionOf(Call
)))));
6433 return ENOENT
; /* is this proper error code? */
6436 * See if the file has several links (from other volumes). If it
6437 * does, then we have to make a copy before changing it to avoid
6438 *changing read-only clones of this dude
6441 ("StoreData_RXStyle : Opening inode %s\n",
6442 PrintInode(stmp
, VN_GET_INO(targetptr
))));
6443 fdP
= IH_OPEN(targetptr
->handle
);
6446 if (GetLinkCountAndSize(volptr
, fdP
, &linkCount
, &DataLength
) < 0) {
6448 VTakeOffline(volptr
);
6449 ViceLog(0, ("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6450 afs_printable_VolumeId_lu(volptr
->hashid
)));
6453 if (CheckLength(volptr
, targetptr
, DataLength
)) {
6455 VTakeOffline(volptr
);
6459 if (linkCount
!= 1) {
6462 ("StoreData_RXStyle : inode %s has more than onelink\n",
6463 PrintInode(stmp
, VN_GET_INO(targetptr
))));
6464 /* other volumes share this data, better copy it first */
6466 /* Adjust the disk block count by the creation of the new inode.
6467 * We call the special VDiskUsage so we don't adjust the volume's
6468 * quota since we don't want to penalyze the user for afs's internal
6469 * mechanisms (i.e. copy on write overhead.) Also the right size
6470 * of the disk will be recorded...
6473 VN_GET_LEN(size
, targetptr
);
6474 volptr
->partition
->flags
&= ~PART_DONTUPDATE
;
6475 VSetPartitionDiskUsage(volptr
->partition
);
6476 volptr
->partition
->flags
|= PART_DONTUPDATE
;
6477 if ((errorCode
= VDiskUsage(volptr
, nBlocks(size
)))) {
6478 volptr
->partition
->flags
&= ~PART_DONTUPDATE
;
6482 ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n"));
6483 if ((errorCode
= CopyOnWrite(targetptr
, volptr
, 0, MAXFSIZE
))) {
6484 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6485 volptr
->partition
->flags
&= ~PART_DONTUPDATE
;
6488 volptr
->partition
->flags
&= ~PART_DONTUPDATE
;
6489 VSetPartitionDiskUsage(volptr
->partition
);
6490 fdP
= IH_OPEN(targetptr
->handle
);
6493 ("StoreData : Reopen after CopyOnWrite failed\n"));
6497 tinode
= VN_GET_INO(targetptr
);
6499 if (!VALID_INO(tinode
)) {
6500 VTakeOffline(volptr
);
6501 ViceLog(0,("Volume %" AFS_VOLID_FMT
" now offline, must be salvaged.\n",
6502 afs_printable_VolumeId_lu(volptr
->hashid
)));
6506 /* compute new file length */
6507 NewLength
= DataLength
;
6508 if (FileLength
< NewLength
)
6509 /* simulate truncate */
6510 NewLength
= FileLength
;
6511 TruncatedLength
= NewLength
; /* remember length after possible ftruncate */
6512 if (Pos
+ Length
> NewLength
)
6513 NewLength
= Pos
+ Length
; /* and write */
6515 /* adjust the disk block count by the difference in the files */
6517 afs_fsize_t targSize
;
6518 VN_GET_LEN(targSize
, targetptr
);
6519 adjustSize
= nBlocks(NewLength
) - nBlocks(targSize
);
6522 AdjustDiskUsage(volptr
, adjustSize
,
6523 adjustSize
- SpareComp(volptr
)))) {
6528 /* can signal cache manager to proceed from close now */
6529 /* this bit means that the locks are set and protections are OK */
6530 rx_SetLocalStatus(Call
, 1);
6532 optSize
= sendBufSize
;
6534 ("StoreData_RXStyle: Pos %llu, DataLength %llu, FileLength %llu, Length %llu\n",
6535 (afs_uintmax_t
) Pos
, (afs_uintmax_t
) DataLength
,
6536 (afs_uintmax_t
) FileLength
, (afs_uintmax_t
) Length
));
6538 bytesTransfered
= 0;
6540 tbuffer
= AllocSendBuffer();
6541 #endif /* HAVE_PIOV */
6542 /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
6543 if (FileLength
< DataLength
) {
6544 errorCode
= FDH_TRUNC(fdP
, FileLength
);
6549 /* if length == 0, the loop below isn't going to do anything, including
6550 * extend the length of the inode, which it must do, since the file system
6551 * assumes that the inode length == vnode's file length. So, we extend
6552 * the file length manually if need be. Note that if file is bigger than
6553 * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
6554 * do what we're going to do below.
6556 if (Length
== 0 && Pos
> TruncatedLength
) {
6557 /* Set the file's length; we've already done an lseek to the right
6560 tlen
= 0; /* Just a source of data for the write */
6561 nBytes
= FDH_PWRITE(fdP
, &tlen
, 1, Pos
);
6566 errorCode
= FDH_TRUNC(fdP
, Pos
);
6568 /* have some data to copy */
6569 (*a_bytesToStoreP
) = Length
;
6572 if (bytesTransfered
>= Length
) {
6576 tlen
= Length
- bytesTransfered
; /* how much more to do */
6578 rlen
= optSize
; /* bound by buffer size */
6582 errorCode
= rx_Read(Call
, tbuffer
, rlen
);
6583 #else /* HAVE_PIOV */
6584 errorCode
= rx_Readv(Call
, tiov
, &tnio
, RX_MAXIOVECS
, rlen
);
6585 #endif /* HAVE_PIOV */
6586 if (errorCode
<= 0) {
6590 (*a_bytesStoredP
) += errorCode
;
6593 nBytes
= FDH_PWRITE(fdP
, tbuffer
, rlen
, Pos
);
6594 #else /* HAVE_PIOV */
6595 nBytes
= FDH_PWRITEV(fdP
, tiov
, tnio
, Pos
);
6596 #endif /* HAVE_PIOV */
6597 if (nBytes
!= rlen
) {
6598 errorCode
= VDISKFULL
;
6601 bytesTransfered
+= rlen
;
6607 FreeSendBuffer((struct afs_buffer
*)tbuffer
);
6608 #endif /* HAVE_PIOV */
6610 (void) FDH_SYNC(fdP
);
6613 Error tmp_errorCode
= 0;
6614 afs_sfsize_t nfSize
= FDH_SIZE(fdP
);
6615 opr_Assert(nfSize
>= 0);
6616 /* something went wrong: adjust size and return */
6617 VN_SET_LEN(targetptr
, nfSize
); /* set new file size. */
6618 /* changed_newTime is tested in StoreData to detemine if we
6619 * need to update the target vnode.
6621 targetptr
->changed_newTime
= 1;
6623 /* set disk usage to be correct */
6624 VAdjustDiskUsage(&tmp_errorCode
, volptr
,
6625 (afs_sfsize_t
) (nBlocks(nfSize
) -
6626 nBlocks(NewLength
)), 0);
6627 if (tmp_errorCode
) {
6628 errorCode
= tmp_errorCode
;
6634 VN_SET_LEN(targetptr
, NewLength
);
6636 /* Update all StoreData related stats */
6638 if (AFSCallStats
.TotalStoredBytes
> 2000000000) /* reset if over 2 billion */
6639 AFSCallStats
.TotalStoredBytes
= AFSCallStats
.AccumStoreTime
= 0;
6640 AFSCallStats
.StoreSize1
++; /* Piggybacked data */
6642 afs_fsize_t targLen
;
6643 VN_GET_LEN(targLen
, targetptr
);
6644 if (targLen
< SIZE2
)
6645 AFSCallStats
.StoreSize2
++;
6646 else if (targLen
< SIZE3
)
6647 AFSCallStats
.StoreSize3
++;
6648 else if (targLen
< SIZE4
)
6649 AFSCallStats
.StoreSize4
++;
6651 AFSCallStats
.StoreSize5
++;
6656 } /*StoreData_RXStyle */
6658 static int sys2et
[512];
6661 init_sys_error_to_et(void)
6663 memset(&sys2et
, 0, sizeof(sys2et
));
6664 sys2et
[EPERM
] = UAEPERM
;
6665 sys2et
[ENOENT
] = UAENOENT
;
6666 sys2et
[ESRCH
] = UAESRCH
;
6667 sys2et
[EINTR
] = UAEINTR
;
6668 sys2et
[EIO
] = UAEIO
;
6669 sys2et
[ENXIO
] = UAENXIO
;
6670 sys2et
[E2BIG
] = UAE2BIG
;
6671 sys2et
[ENOEXEC
] = UAENOEXEC
;
6672 sys2et
[EBADF
] = UAEBADF
;
6673 sys2et
[ECHILD
] = UAECHILD
;
6674 sys2et
[EAGAIN
] = UAEAGAIN
;
6675 sys2et
[ENOMEM
] = UAENOMEM
;
6676 sys2et
[EACCES
] = UAEACCES
;
6677 sys2et
[EFAULT
] = UAEFAULT
;
6678 sys2et
[ENOTBLK
] = UAENOTBLK
;
6679 sys2et
[EBUSY
] = UAEBUSY
;
6680 sys2et
[EEXIST
] = UAEEXIST
;
6681 sys2et
[EXDEV
] = UAEXDEV
;
6682 sys2et
[ENODEV
] = UAENODEV
;
6683 sys2et
[ENOTDIR
] = UAENOTDIR
;
6684 sys2et
[EISDIR
] = UAEISDIR
;
6685 sys2et
[EINVAL
] = UAEINVAL
;
6686 sys2et
[ENFILE
] = UAENFILE
;
6687 sys2et
[EMFILE
] = UAEMFILE
;
6688 sys2et
[ENOTTY
] = UAENOTTY
;
6689 sys2et
[ETXTBSY
] = UAETXTBSY
;
6690 sys2et
[EFBIG
] = UAEFBIG
;
6691 sys2et
[ENOSPC
] = UAENOSPC
;
6692 sys2et
[ESPIPE
] = UAESPIPE
;
6693 sys2et
[EROFS
] = UAEROFS
;
6694 sys2et
[EMLINK
] = UAEMLINK
;
6695 sys2et
[EPIPE
] = UAEPIPE
;
6696 sys2et
[EDOM
] = UAEDOM
;
6697 sys2et
[ERANGE
] = UAERANGE
;
6698 sys2et
[EDEADLK
] = UAEDEADLK
;
6699 sys2et
[ENAMETOOLONG
] = UAENAMETOOLONG
;
6700 sys2et
[ENOLCK
] = UAENOLCK
;
6701 sys2et
[ENOSYS
] = UAENOSYS
;
6702 #if (ENOTEMPTY != EEXIST)
6703 sys2et
[ENOTEMPTY
] = UAENOTEMPTY
;
6705 sys2et
[ELOOP
] = UAELOOP
;
6706 #if (EWOULDBLOCK != EAGAIN)
6707 sys2et
[EWOULDBLOCK
] = UAEWOULDBLOCK
;
6709 sys2et
[ENOMSG
] = UAENOMSG
;
6710 sys2et
[EIDRM
] = UAEIDRM
;
6711 sys2et
[ECHRNG
] = UAECHRNG
;
6712 sys2et
[EL2NSYNC
] = UAEL2NSYNC
;
6713 sys2et
[EL3HLT
] = UAEL3HLT
;
6714 sys2et
[EL3RST
] = UAEL3RST
;
6715 sys2et
[ELNRNG
] = UAELNRNG
;
6716 sys2et
[EUNATCH
] = UAEUNATCH
;
6717 sys2et
[ENOCSI
] = UAENOCSI
;
6718 sys2et
[EL2HLT
] = UAEL2HLT
;
6719 sys2et
[EBADE
] = UAEBADE
;
6720 sys2et
[EBADR
] = UAEBADR
;
6721 sys2et
[EXFULL
] = UAEXFULL
;
6722 sys2et
[ENOANO
] = UAENOANO
;
6723 sys2et
[EBADRQC
] = UAEBADRQC
;
6724 sys2et
[EBADSLT
] = UAEBADSLT
;
6725 sys2et
[EDEADLK
] = UAEDEADLK
;
6726 sys2et
[EBFONT
] = UAEBFONT
;
6727 sys2et
[ENOSTR
] = UAENOSTR
;
6728 sys2et
[ENODATA
] = UAENODATA
;
6729 sys2et
[ETIME
] = UAETIME
;
6730 sys2et
[ENOSR
] = UAENOSR
;
6731 sys2et
[ENONET
] = UAENONET
;
6732 sys2et
[ENOPKG
] = UAENOPKG
;
6733 sys2et
[EREMOTE
] = UAEREMOTE
;
6734 sys2et
[ENOLINK
] = UAENOLINK
;
6735 sys2et
[EADV
] = UAEADV
;
6736 sys2et
[ESRMNT
] = UAESRMNT
;
6737 sys2et
[ECOMM
] = UAECOMM
;
6738 sys2et
[EPROTO
] = UAEPROTO
;
6739 sys2et
[EMULTIHOP
] = UAEMULTIHOP
;
6740 sys2et
[EDOTDOT
] = UAEDOTDOT
;
6741 sys2et
[EBADMSG
] = UAEBADMSG
;
6742 sys2et
[EOVERFLOW
] = UAEOVERFLOW
;
6743 sys2et
[ENOTUNIQ
] = UAENOTUNIQ
;
6744 sys2et
[EBADFD
] = UAEBADFD
;
6745 sys2et
[EREMCHG
] = UAEREMCHG
;
6746 sys2et
[ELIBACC
] = UAELIBACC
;
6747 sys2et
[ELIBBAD
] = UAELIBBAD
;
6748 sys2et
[ELIBSCN
] = UAELIBSCN
;
6749 sys2et
[ELIBMAX
] = UAELIBMAX
;
6750 sys2et
[ELIBEXEC
] = UAELIBEXEC
;
6751 sys2et
[EILSEQ
] = UAEILSEQ
;
6752 sys2et
[ERESTART
] = UAERESTART
;
6753 sys2et
[ESTRPIPE
] = UAESTRPIPE
;
6754 sys2et
[EUSERS
] = UAEUSERS
;
6755 sys2et
[ENOTSOCK
] = UAENOTSOCK
;
6756 sys2et
[EDESTADDRREQ
] = UAEDESTADDRREQ
;
6757 sys2et
[EMSGSIZE
] = UAEMSGSIZE
;
6758 sys2et
[EPROTOTYPE
] = UAEPROTOTYPE
;
6759 sys2et
[ENOPROTOOPT
] = UAENOPROTOOPT
;
6760 sys2et
[EPROTONOSUPPORT
] = UAEPROTONOSUPPORT
;
6761 sys2et
[ESOCKTNOSUPPORT
] = UAESOCKTNOSUPPORT
;
6762 sys2et
[EOPNOTSUPP
] = UAEOPNOTSUPP
;
6763 sys2et
[EPFNOSUPPORT
] = UAEPFNOSUPPORT
;
6764 sys2et
[EAFNOSUPPORT
] = UAEAFNOSUPPORT
;
6765 sys2et
[EADDRINUSE
] = UAEADDRINUSE
;
6766 sys2et
[EADDRNOTAVAIL
] = UAEADDRNOTAVAIL
;
6767 sys2et
[ENETDOWN
] = UAENETDOWN
;
6768 sys2et
[ENETUNREACH
] = UAENETUNREACH
;
6769 sys2et
[ENETRESET
] = UAENETRESET
;
6770 sys2et
[ECONNABORTED
] = UAECONNABORTED
;
6771 sys2et
[ECONNRESET
] = UAECONNRESET
;
6772 sys2et
[ENOBUFS
] = UAENOBUFS
;
6773 sys2et
[EISCONN
] = UAEISCONN
;
6774 sys2et
[ENOTCONN
] = UAENOTCONN
;
6775 sys2et
[ESHUTDOWN
] = UAESHUTDOWN
;
6776 sys2et
[ETOOMANYREFS
] = UAETOOMANYREFS
;
6777 sys2et
[ETIMEDOUT
] = UAETIMEDOUT
;
6778 sys2et
[ECONNREFUSED
] = UAECONNREFUSED
;
6779 sys2et
[EHOSTDOWN
] = UAEHOSTDOWN
;
6780 sys2et
[EHOSTUNREACH
] = UAEHOSTUNREACH
;
6781 sys2et
[EALREADY
] = UAEALREADY
;
6782 sys2et
[EINPROGRESS
] = UAEINPROGRESS
;
6783 sys2et
[ESTALE
] = UAESTALE
;
6784 sys2et
[EUCLEAN
] = UAEUCLEAN
;
6785 sys2et
[ENOTNAM
] = UAENOTNAM
;
6786 sys2et
[ENAVAIL
] = UAENAVAIL
;
6787 sys2et
[EISNAM
] = UAEISNAM
;
6788 sys2et
[EREMOTEIO
] = UAEREMOTEIO
;
6789 sys2et
[EDQUOT
] = UAEDQUOT
;
6790 sys2et
[ENOMEDIUM
] = UAENOMEDIUM
;
6791 sys2et
[EMEDIUMTYPE
] = UAEMEDIUMTYPE
;
6793 sys2et
[EIO
] = UAEIO
;
6797 * SRXAFS_CallBackRxConnAddr should be re-written as follows:
6798 * - pass back the connection, client, and host from CallPreamble
6799 * - keep a ref on the client, which we don't now
6800 * - keep a hold on the host, which we already do
6801 * - pass the connection, client, and host down into SAFSS_*, and use
6802 * them instead of independently discovering them via rx_ConnectionOf
6803 * (safe) and rx_GetSpecific (not so safe)
6804 * The idea being that we decide what client and host we're going to use
6805 * when CallPreamble is called, and stay consistent throughout the call.
6806 * This change is too invasive for 1.4.1 but should be made in 1.5.x.
6810 SRXAFS_CallBackRxConnAddr (struct rx_call
* acall
, afs_int32
*addr
)
6812 Error errorCode
= 0;
6813 struct rx_connection
*tcon
;
6814 struct host
*tcallhost
;
6815 #ifdef __EXPERIMENTAL_CALLBACK_CONN_MOVING
6817 struct client
*tclient
;
6818 static struct rx_securityClass
*sc
= 0;
6820 struct rx_connection
*conn
;
6821 afs_int32 viceid
= -1;
6824 if ((errorCode
= CallPreamble(acall
, ACTIVECALL
, NULL
, &tcon
, &tcallhost
)))
6825 goto Bad_CallBackRxConnAddr1
;
6827 #ifndef __EXPERIMENTAL_CALLBACK_CONN_MOVING
6831 tclient
= h_FindClient_r(tcon
, &viceid
);
6834 LogClientError("Client host too busy (CallBackRxConnAddr)", tcon
, viceid
, NULL
);
6835 goto Bad_CallBackRxConnAddr
;
6837 thost
= tclient
->z
.host
;
6839 /* nothing more can be done */
6840 if ( !thost
->z
.interface
)
6841 goto Bad_CallBackRxConnAddr
;
6843 /* the only address is the primary interface */
6844 /* can't change when there's only 1 address, anyway */
6845 if ( thost
->z
.interface
->numberOfInterfaces
<= 1 )
6846 goto Bad_CallBackRxConnAddr
;
6848 /* initialise a security object only once */
6850 sc
= (struct rx_securityClass
*) rxnull_NewClientSecurityObject();
6852 for ( i
=0; i
< thost
->z
.interface
->numberOfInterfaces
; i
++)
6854 if ( *addr
== thost
->z
.interface
->addr
[i
] ) {
6859 if ( *addr
!= thost
->z
.interface
->addr
[i
] )
6860 goto Bad_CallBackRxConnAddr
;
6862 conn
= rx_NewConnection (thost
->z
.interface
->addr
[i
],
6863 thost
->z
.port
, 1, sc
, 0);
6864 rx_SetConnDeadTime(conn
, 2);
6865 rx_SetConnHardDeadTime(conn
, AFS_HARDDEADTIME
);
6867 errorCode
= RXAFSCB_Probe(conn
);
6870 if ( thost
->z
.callback_rxcon
)
6871 rx_DestroyConnection(thost
->z
.callback_rxcon
);
6872 thost
->z
.callback_rxcon
= conn
;
6873 thost
->z
.host
= addr
;
6874 rx_SetConnDeadTime(thost
->z
.callback_rxcon
, 50);
6875 rx_SetConnHardDeadTime(thost
->z
.callback_rxcon
, AFS_HARDDEADTIME
);
6876 h_ReleaseClient_r(tclient
);
6877 /* The hold on thost will be released by CallPostamble */
6879 errorCode
= CallPostamble(tcon
, errorCode
, tcallhost
);
6882 rx_DestroyConnection(conn
);
6884 Bad_CallBackRxConnAddr
:
6885 h_ReleaseClient_r(tclient
);
6886 /* The hold on thost will be released by CallPostamble */
6890 errorCode
= CallPostamble(tcon
, errorCode
, tcallhost
);
6891 Bad_CallBackRxConnAddr1
:
6892 return errorCode
; /* failure */
6896 sys_error_to_et(afs_int32 in
)
6900 if (in
< 0 || in
> 511)
6902 if ((in
>= VICE_SPECIAL_ERRORS
&& in
<= VIO
) || in
== VRESTRICTED
)
6904 if (sys2et
[in
] != 0)