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
19 * afs_FlushActiveVcaches
38 #include <afsconfig.h>
39 #include "afs/param.h"
44 #include "afs/sysincludes.h" /*Standard vendor system headers */
45 #include "afsincludes.h" /*AFS-based standard headers */
46 #include "afs/afs_stats.h"
47 #include "afs/afs_cbqueue.h"
48 #include "afs/afs_osidnlc.h"
51 afs_int32 afs_maxvcount = 0; /* max number of vcache entries */
52 afs_int32 afs_vcount = 0; /* number of vcache in use now */
53 #endif /* AFS_OSF_ENV */
61 #endif /* AFS_SGI64_ENV */
63 /* Exported variables */
64 afs_rwlock_t afs_xvcache; /*Lock: alloc new stat cache entries */
65 afs_lock_t afs_xvcb; /*Lock: fids on which there are callbacks */
66 struct vcache *freeVCList; /*Free list for stat cache entries */
67 struct vcache *Initial_freeVCList; /*Initial list for above */
68 struct afs_q VLRU; /*vcache LRU */
69 afs_int32 vcachegen = 0;
70 unsigned int afs_paniconwarn = 0;
71 struct vcache *afs_vhashT[VCSIZE];
72 afs_int32 afs_bulkStatsLost;
73 int afs_norefpanic = 0;
75 /* Forward declarations */
76 static afs_int32 afs_QueueVCB(struct vcache *avc);
83 * Flush the given vcache entry.
86 * avc : Pointer to vcache entry to flush.
87 * slept : Pointer to int to set 1 if we sleep/drop locks, 0 if we don't.
90 * afs_xvcache lock must be held for writing upon entry to
91 * prevent people from changing the vrefCount field, and to
92 * protect the lruq and hnext fields.
93 * LOCK: afs_FlushVCache afs_xvcache W
94 * REFCNT: vcache ref count must be zero on entry except for osf1
95 * RACE: lock is dropped and reobtained, permitting race in caller
99 afs_FlushVCache(struct vcache *avc, int *slept)
100 { /*afs_FlushVCache */
102 register afs_int32 i, code;
103 register struct vcache **uvc, *wvc;
106 AFS_STATCNT(afs_FlushVCache);
107 afs_Trace2(afs_iclSetp, CM_TRACE_FLUSHV, ICL_TYPE_POINTER, avc,
108 ICL_TYPE_INT32, avc->states);
111 VN_LOCK(AFSTOV(avc));
115 code = osi_VM_FlushVCache(avc, slept);
119 if (avc->states & CVFlushed) {
123 if (avc->nextfree || !avc->vlruq.prev || !avc->vlruq.next) { /* qv afs.h */
124 refpanic("LRU vs. Free inconsistency");
126 avc->states |= CVFlushed;
127 /* pull the entry out of the lruq and put it on the free list */
128 QRemove(&avc->vlruq);
129 avc->vlruq.prev = avc->vlruq.next = (struct afs_q *)0;
131 /* keep track of # of files that we bulk stat'd, but never used
132 * before they got recycled.
134 if (avc->states & CBulkStat)
137 /* remove entry from the hash chain */
138 i = VCHash(&avc->fid);
139 uvc = &afs_vhashT[i];
140 for (wvc = *uvc; wvc; uvc = &wvc->hnext, wvc = *uvc) {
143 avc->hnext = (struct vcache *)NULL;
148 osi_Panic("flushvcache"); /* not in correct hash bucket */
150 osi_FreeSmallSpace(avc->mvid);
151 avc->mvid = (struct VenusFid *)0;
153 afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
154 avc->linkData = NULL;
156 #if defined(AFS_XBSD_ENV)
157 /* OK, there are no internal vrefCounts, so there shouldn't
158 * be any more refs here. */
160 avc->v->v_data = NULL; /* remove from vnode */
161 avc->v = NULL; /* also drop the ptr to vnode */
164 afs_FreeAllAxs(&(avc->Access));
166 /* we can't really give back callbacks on RO files, since the
167 * server only tracks them on a per-volume basis, and we don't
168 * know whether we still have some other files from the same
170 if ((avc->states & CRO) == 0 && avc->callback) {
173 ObtainWriteLock(&afs_xcbhash, 460);
174 afs_DequeueCallback(avc); /* remove it from queued callbacks list */
175 avc->states &= ~(CStatd | CUnique);
176 ReleaseWriteLock(&afs_xcbhash);
177 afs_symhint_inval(avc);
178 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
179 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
181 osi_dnlc_purgevp(avc);
184 * Next, keep track of which vnodes we've deleted for create's
185 * optimistic synchronization algorithm
188 if (avc->fid.Fid.Vnode & 1)
193 #if !defined(AFS_OSF_ENV)
194 /* put the entry in the free list */
195 avc->nextfree = freeVCList;
197 if (avc->vlruq.prev || avc->vlruq.next) {
198 refpanic("LRU vs. Free inconsistency");
201 /* This should put it back on the vnode free list since usecount is 1 */
204 if (VREFCOUNT(avc) > 0) {
205 VN_UNLOCK(AFSTOV(avc));
206 AFS_RELE(AFSTOV(avc));
208 if (afs_norefpanic) {
209 printf("flush vc refcnt < 1");
211 (void)vgone(avc, VX_NOSLEEP, NULL);
213 VN_UNLOCK(AFSTOV(avc));
215 osi_Panic("flush vc refcnt < 1");
217 #endif /* AFS_OSF_ENV */
218 avc->states |= CVFlushed;
223 VN_UNLOCK(AFSTOV(avc));
227 } /*afs_FlushVCache */
233 * The core of the inactive vnode op for all but IRIX.
236 afs_InactiveVCache(struct vcache *avc, struct AFS_UCRED *acred)
238 AFS_STATCNT(afs_inactive);
239 if (avc->states & CDirty) {
240 /* we can't keep trying to push back dirty data forever. Give up. */
241 afs_InvalidateAllSegments(avc); /* turns off dirty bit */
243 avc->states &= ~CMAPPED; /* mainly used by SunOS 4.0.x */
244 avc->states &= ~CDirty; /* Turn it off */
245 if (avc->states & CUnlinked) {
246 if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache)) {
247 avc->states |= CUnlinkedDel;
250 afs_remunlink(avc, 1); /* ignore any return code */
259 * Description: allocate a callback return structure from the
260 * free list and return it.
262 * Env: The alloc and free routines are both called with the afs_xvcb lock
263 * held, so we don't have to worry about blocking in osi_Alloc.
265 static struct afs_cbr *afs_cbrSpace = 0;
269 register struct afs_cbr *tsp;
272 while (!afs_cbrSpace) {
273 if (afs_stats_cmperf.CallBackAlloced >= 2) {
274 /* don't allocate more than 2 * AFS_NCBRS for now */
276 afs_stats_cmperf.CallBackFlushes++;
280 (struct afs_cbr *)afs_osi_Alloc(AFS_NCBRS *
281 sizeof(struct afs_cbr));
282 for (i = 0; i < AFS_NCBRS - 1; i++) {
283 tsp[i].next = &tsp[i + 1];
285 tsp[AFS_NCBRS - 1].next = 0;
287 afs_stats_cmperf.CallBackAlloced++;
291 afs_cbrSpace = tsp->next;
298 * Description: free a callback return structure.
301 * asp -- the address of the structure to free.
303 * Environment: the xvcb lock is held over these calls.
306 afs_FreeCBR(register struct afs_cbr *asp)
308 asp->next = afs_cbrSpace;
316 * Description: flush all queued callbacks to all servers.
320 * Environment: holds xvcb lock over RPC to guard against race conditions
321 * when a new callback is granted for the same file later on.
324 afs_FlushVCBs(afs_int32 lockit)
326 struct AFSFid *tfids;
327 struct AFSCallBack callBacks[1];
328 struct AFSCBFids fidArray;
329 struct AFSCBs cbArray;
331 struct afs_cbr *tcbrp;
335 struct vrequest treq;
337 int safety1, safety2, safety3;
338 XSTATS_DECLS if ((code = afs_InitReq(&treq, afs_osi_credp)))
340 treq.flags |= O_NONBLOCK;
341 tfids = afs_osi_Alloc(sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
344 MObtainWriteLock(&afs_xvcb, 273);
345 ObtainReadLock(&afs_xserver);
346 for (i = 0; i < NSERVERS; i++) {
347 for (safety1 = 0, tsp = afs_servers[i];
348 tsp && safety1 < afs_totalServers + 10;
349 tsp = tsp->next, safety1++) {
351 if (tsp->cbrs == (struct afs_cbr *)0)
354 /* otherwise, grab a block of AFS_MAXCBRSCALL from the list
355 * and make an RPC, over and over again.
357 tcount = 0; /* number found so far */
358 for (safety2 = 0; safety2 < afs_cacheStats; safety2++) {
359 if (tcount >= AFS_MAXCBRSCALL || !tsp->cbrs) {
360 /* if buffer is full, or we've queued all we're going
361 * to from this server, we should flush out the
364 fidArray.AFSCBFids_len = tcount;
365 fidArray.AFSCBFids_val = (struct AFSFid *)tfids;
366 cbArray.AFSCBs_len = 1;
367 cbArray.AFSCBs_val = callBacks;
368 memset(&callBacks[0], 0, sizeof(callBacks[0]));
369 callBacks[0].CallBackType = CB_EXCLUSIVE;
370 for (safety3 = 0; safety3 < MAXHOSTS * 2; safety3++) {
371 tc = afs_ConnByHost(tsp, tsp->cell->fsport,
372 tsp->cell->cellNum, &treq, 0,
376 (AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
379 RXAFS_GiveUpCallBacks(tc->id, &fidArray,
387 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK,
392 /* ignore return code, since callbacks may have
393 * been returned anyway, we shouldn't leave them
394 * around to be returned again.
396 * Next, see if we are done with this server, and if so,
397 * break to deal with the next one.
403 /* if to flush full buffer */
404 /* if we make it here, we have an entry at the head of cbrs,
405 * which we should copy to the file ID array and then free.
408 tfids[tcount++] = tcbrp->fid;
409 tsp->cbrs = tcbrp->next;
411 } /* while loop for this one server */
412 if (safety2 > afs_cacheStats) {
413 afs_warn("possible internal error afs_flushVCBs (%d)\n",
416 } /* for loop for this hash chain */
417 } /* loop through all hash chains */
418 if (safety1 > afs_totalServers + 2) {
420 ("AFS internal error (afs_flushVCBs) (%d > %d), continuing...\n",
421 safety1, afs_totalServers + 2);
423 osi_Panic("afs_flushVCBS safety1");
426 ReleaseReadLock(&afs_xserver);
428 MReleaseWriteLock(&afs_xvcb);
429 afs_osi_Free(tfids, sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
437 * Queue a callback on the given fid.
443 * Locks the xvcb lock.
444 * Called when the xvcache lock is already held.
448 afs_QueueVCB(struct vcache *avc)
450 register struct server *tsp;
451 register struct afs_cbr *tcbp;
453 AFS_STATCNT(afs_QueueVCB);
454 /* The callback is really just a struct server ptr. */
455 tsp = (struct server *)(avc->callback);
457 /* we now have a pointer to the server, so we just allocate
458 * a queue entry and queue it.
460 MObtainWriteLock(&afs_xvcb, 274);
461 tcbp = afs_AllocCBR();
462 tcbp->fid = avc->fid.Fid;
463 tcbp->next = tsp->cbrs;
466 /* now release locks and return */
467 MReleaseWriteLock(&afs_xvcb);
476 * Remove a queued callback by looking through all the servers
477 * to see if any have this callback queued.
480 * afid: The fid we want cleansed of queued callbacks.
483 * Locks xvcb and xserver locks.
484 * Typically called with xdcache, xvcache and/or individual vcache
489 afs_RemoveVCB(struct VenusFid *afid)
492 register struct server *tsp;
493 register struct afs_cbr *tcbrp;
494 struct afs_cbr **lcbrpp;
496 AFS_STATCNT(afs_RemoveVCB);
497 MObtainWriteLock(&afs_xvcb, 275);
498 ObtainReadLock(&afs_xserver);
499 for (i = 0; i < NSERVERS; i++) {
500 for (tsp = afs_servers[i]; tsp; tsp = tsp->next) {
501 /* if cell is known, and is wrong, then skip this server */
502 if (tsp->cell && tsp->cell->cellNum != afid->Cell)
506 * Otherwise, iterate through file IDs we're sending to the
509 lcbrpp = &tsp->cbrs; /* first queued return callback */
510 for (tcbrp = *lcbrpp; tcbrp;
511 lcbrpp = &tcbrp->next, tcbrp = *lcbrpp) {
512 if (afid->Fid.Volume == tcbrp->fid.Volume
513 && afid->Fid.Unique == tcbrp->fid.Unique
514 && afid->Fid.Vnode == tcbrp->fid.Vnode) {
515 *lcbrpp = tcbrp->next; /* unthread from list */
523 ReleaseReadLock(&afs_xserver);
524 MReleaseWriteLock(&afs_xvcb);
528 #if defined(AFS_LINUX22_ENV) && !defined(AFS_LINUX26_ENV)
531 __shrink_dcache_parent(struct dentry *parent)
533 struct dentry *this_parent = parent;
534 struct list_head *next;
536 LIST_HEAD(afs_dentry_unused);
539 next = this_parent->d_subdirs.next;
541 while (next != &this_parent->d_subdirs) {
542 struct list_head *tmp = next;
543 struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
545 if (!DCOUNT(dentry)) {
546 list_del(&dentry->d_lru);
547 list_add(&dentry->d_lru, afs_dentry_unused.prev);
551 * Descend a level if the d_subdirs list is non-empty.
553 if (!list_empty(&dentry->d_subdirs)) {
554 this_parent = dentry;
559 * All done at this level ... ascend and resume the search.
561 if (this_parent != parent) {
562 next = this_parent->d_child.next;
563 this_parent = this_parent->d_parent;
568 struct dentry *dentry;
569 struct list_head *tmp;
571 tmp = afs_dentry_unused.prev;
573 if (tmp == &afs_dentry_unused)
575 #ifdef AFS_LINUX24_ENV
580 #endif /* AFS_LINUX24_ENV */
581 dentry = list_entry(tmp, struct dentry, d_lru);
583 #ifdef AFS_LINUX24_ENV
584 /* Unused dentry with a count? */
589 #ifdef AFS_LINUX24_ENV
590 list_del_init(&dentry->d_hash); /* d_drop */
592 list_del(&dentry->d_hash);
593 INIT_LIST_HEAD(&dentry->d_hash);
594 #endif /* AFS_LINUX24_ENV */
603 /* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
604 * children of the dentry
606 * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
607 * AFS_GLOCK, so it can call dput, which may call iput, but
608 * keeps afs_xvcache exclusively.
610 * Tree traversal algorithm from fs/dcache.c: select_parent()
613 afs_TryFlushDcacheChildren(struct vcache *tvc)
615 struct inode *ip = AFSTOI(tvc);
616 struct dentry *this_parent;
617 struct list_head *next;
618 struct list_head *cur;
619 struct list_head *head = &ip->i_dentry;
620 struct dentry *dentry;
624 #ifndef old_vcache_scheme
627 while ((cur = cur->next) != head) {
628 dentry = list_entry(cur, struct dentry, d_alias);
630 afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN,
631 ICL_TYPE_POINTER, ip, ICL_TYPE_STRING,
632 dentry->d_parent->d_name.name, ICL_TYPE_STRING,
633 dentry->d_name.name);
635 if (!list_empty(&dentry->d_hash) && !list_empty(&dentry->d_subdirs))
636 __shrink_dcache_parent(dentry);
638 if (!DCOUNT(dentry)) {
640 #ifdef AFS_LINUX24_ENV
641 list_del_init(&dentry->d_hash); /* d_drop */
643 list_del(&dentry->d_hash);
644 INIT_LIST_HEAD(&dentry->d_hash);
645 #endif /* AFS_LINUX24_ENV */
657 while ((cur = cur->next) != head) {
658 dentry = list_entry(cur, struct dentry, d_alias);
660 afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN,
661 ICL_TYPE_POINTER, ip, ICL_TYPE_STRING,
662 dentry->d_parent->d_name.name, ICL_TYPE_STRING,
663 dentry->d_name.name);
665 if (!DCOUNT(dentry)) {
678 #endif /* AFS_LINUX22_ENV && !AFS_LINUX26_ENV */
684 * This routine is responsible for allocating a new cache entry
685 * from the free list. It formats the cache entry and inserts it
686 * into the appropriate hash tables. It must be called with
687 * afs_xvcache write-locked so as to prevent several processes from
688 * trying to create a new cache entry simultaneously.
691 * afid : The file id of the file whose cache entry is being
694 /* LOCK: afs_NewVCache afs_xvcache W */
696 afs_NewVCache(struct VenusFid *afid, struct server *serverp)
700 afs_int32 anumber = VCACHE_FREE;
702 struct gnode *gnodepnt;
705 struct vm_info *vm_info_ptr;
706 #endif /* AFS_MACH_ENV */
709 #endif /* AFS_OSF_ENV */
710 struct afs_q *tq, *uq;
713 AFS_STATCNT(afs_NewVCache);
716 if (afs_vcount >= afs_maxvcount) {
719 * If we are using > 33 % of the total system vnodes for AFS vcache
720 * entries or we are using the maximum number of vcache entries,
721 * then free some. (if our usage is > 33% we should free some, if
722 * our usage is > afs_maxvcount, set elsewhere to 0.5*nvnode,
723 * we _must_ free some -- no choice).
725 if (((3 * afs_vcount) > nvnode) || (afs_vcount >= afs_maxvcount)) {
727 struct afs_q *tq, *uq;
732 for (tq = VLRU.prev; tq != &VLRU && anumber > 0; tq = uq) {
735 if (tvc->states & CVFlushed)
736 refpanic("CVFlushed on VLRU");
737 else if (i++ > afs_maxvcount)
738 refpanic("Exceeded pool of AFS vnodes(VLRU cycle?)");
739 else if (QNext(uq) != tq)
740 refpanic("VLRU inconsistent");
741 else if (VREFCOUNT(tvc) < 1)
742 refpanic("refcnt 0 on VLRU");
744 if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
745 && (tvc->states & CUnlinkedDel) == 0) {
746 code = afs_FlushVCache(tvc, &fv_slept);
753 continue; /* start over - may have raced. */
759 if (anumber == VCACHE_FREE) {
760 printf("NewVCache: warning none freed, using %d of %d\n",
761 afs_vcount, afs_maxvcount);
762 if (afs_vcount >= afs_maxvcount) {
763 osi_Panic("NewVCache - none freed");
764 /* XXX instead of panicing, should do afs_maxvcount++
765 * and magic up another one */
771 if (getnewvnode(MOUNT_AFS, &Afs_vnodeops, &nvc)) {
772 /* What should we do ???? */
773 osi_Panic("afs_NewVCache: no more vnodes");
778 tvc->nextfree = NULL;
780 #else /* AFS_OSF_ENV */
781 /* pull out a free cache entry */
784 for (tq = VLRU.prev; (anumber > 0) && (tq != &VLRU); tq = uq) {
788 if (tvc->states & CVFlushed) {
789 refpanic("CVFlushed on VLRU");
790 } else if (i++ > 2 * afs_cacheStats) { /* even allowing for a few xallocs... */
791 refpanic("Increase -stat parameter of afsd(VLRU cycle?)");
792 } else if (QNext(uq) != tq) {
793 refpanic("VLRU inconsistent");
795 #ifdef AFS_DARWIN_ENV
796 if (tvc->opens == 0 && ((tvc->states & CUnlinkedDel) == 0)
797 && VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
798 osi_VM_TryReclaim(tvc, &fv_slept);
802 continue; /* start over - may have raced. */
805 #elif defined(AFS_LINUX22_ENV)
806 if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0) {
807 #if defined(AFS_LINUX26_ENV)
809 d_prune_aliases(AFSTOI(tvc));
812 afs_TryFlushDcacheChildren(tvc);
817 if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
818 && (tvc->states & CUnlinkedDel) == 0) {
819 #if defined(AFS_XBSD_ENV)
821 * vgone() reclaims the vnode, which calls afs_FlushVCache(),
822 * then it puts the vnode on the free list.
823 * If we don't do this we end up with a cleaned vnode that's
824 * not on the free list.
825 * XXX assume FreeBSD is the same for now.
830 code = afs_FlushVCache(tvc, &fv_slept);
838 continue; /* start over - may have raced. */
846 /* none free, making one is better than a panic */
847 afs_stats_cmperf.vcacheXAllocs++; /* count in case we have a leak */
848 tvc = (struct vcache *)afs_osi_Alloc(sizeof(struct vcache));
849 #ifdef KERNEL_HAVE_PIN
850 pin((char *)tvc, sizeof(struct vcache)); /* XXX */
853 /* In case it still comes here we need to fill this */
854 tvc->v.v_vm_info = VM_INFO_NULL;
855 vm_info_init(tvc->v.v_vm_info);
856 /* perhaps we should also do close_flush on non-NeXT mach systems;
857 * who knows; we don't currently have the sources.
859 #endif /* AFS_MACH_ENV */
860 #if defined(AFS_SGI_ENV)
862 char name[METER_NAMSZ];
863 memset(tvc, 0, sizeof(struct vcache));
864 tvc->v.v_number = ++afsvnumbers;
865 tvc->vc_rwlockid = OSI_NO_LOCKID;
866 initnsema(&tvc->vc_rwlock, 1,
867 makesname(name, "vrw", tvc->v.v_number));
868 #ifndef AFS_SGI53_ENV
869 initnsema(&tvc->v.v_sync, 0,
870 makesname(name, "vsy", tvc->v.v_number));
872 #ifndef AFS_SGI62_ENV
873 initnlock(&tvc->v.v_lock,
874 makesname(name, "vlk", tvc->v.v_number));
877 #endif /* AFS_SGI_ENV */
879 tvc = freeVCList; /* take from free list */
880 freeVCList = tvc->nextfree;
881 tvc->nextfree = NULL;
883 #endif /* AFS_OSF_ENV */
886 vm_info_ptr = tvc->v.v_vm_info;
887 #endif /* AFS_MACH_ENV */
889 #if defined(AFS_XBSD_ENV)
891 panic("afs_NewVCache(): free vcache with vnode attached");
894 #if !defined(AFS_SGI_ENV) && !defined(AFS_OSF_ENV)
895 memset((char *)tvc, 0, sizeof(struct vcache));
900 RWLOCK_INIT(&tvc->lock, "vcache lock");
901 #if defined(AFS_SUN5_ENV)
902 RWLOCK_INIT(&tvc->vlock, "vcache vlock");
903 #endif /* defined(AFS_SUN5_ENV) */
906 tvc->v.v_vm_info = vm_info_ptr;
907 tvc->v.v_vm_info->pager = MEMORY_OBJECT_NULL;
908 #endif /* AFS_MACH_ENV */
911 afs_nbsd_getnewvnode(tvc); /* includes one refcount */
913 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
920 #ifdef AFS_FBSD50_ENV
921 if (getnewvnode(MOUNT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
923 if (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
925 panic("afs getnewvnode"); /* can't happen */
927 if (tvc->v != NULL) {
928 /* I'd like to know if this ever happens...
929 We don't drop global for the rest of this function,
930 so if we do lose the race, the other thread should
931 have found the same vnode and finished initializing
932 the vcache entry. Is it conceivable that this vcache
933 entry could be recycled during this interval? If so,
934 then there probably needs to be some sort of additional
935 mutual exclusion (an Embryonic flag would suffice).
937 printf("afs_NewVCache: lost the race\n");
941 tvc->v->v_data = tvc;
942 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
945 tvc->parentVnode = 0;
947 tvc->linkData = NULL;
950 tvc->execsOrWriters = 0;
954 tvc->last_looker = 0;
956 tvc->asynchrony = -1;
958 afs_symhint_inval(tvc);
960 tvc->flushDV.low = tvc->flushDV.high = AFS_MAXDV;
963 tvc->truncPos = AFS_NOTRUNC; /* don't truncate until we need to */
964 hzero(tvc->m.DataVersion); /* in case we copy it into flushDV */
965 #if defined(AFS_LINUX22_ENV)
967 struct inode *ip = AFSTOI(tvc);
968 struct address_space *mapping = &ip->i_data;
970 #if defined(AFS_LINUX26_ENV)
973 sema_init(&ip->i_sem, 1);
974 INIT_LIST_HEAD(&ip->i_hash);
975 INIT_LIST_HEAD(&ip->i_dentry);
976 #if defined(AFS_LINUX24_ENV)
977 sema_init(&ip->i_zombie, 1);
978 init_waitqueue_head(&ip->i_wait);
979 spin_lock_init(&ip->i_data.i_shared_lock);
980 #ifdef STRUCT_ADDRESS_SPACE_HAS_PAGE_LOCK
981 spin_lock_init(&ip->i_data.page_lock);
983 INIT_LIST_HEAD(&ip->i_data.clean_pages);
984 INIT_LIST_HEAD(&ip->i_data.dirty_pages);
985 INIT_LIST_HEAD(&ip->i_data.locked_pages);
986 INIT_LIST_HEAD(&ip->i_dirty_buffers);
987 #ifdef STRUCT_INODE_HAS_I_DIRTY_DATA_BUFFERS
988 INIT_LIST_HEAD(&ip->i_dirty_data_buffers);
990 #ifdef STRUCT_INODE_HAS_I_DEVICES
991 INIT_LIST_HEAD(&ip->i_devices);
993 #ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
994 init_rwsem(&ip->i_truncate_sem);
996 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
997 init_rwsem(&ip->i_alloc_sem);
1000 #else /* AFS_LINUX22_ENV */
1001 sema_init(&ip->i_atomic_write, 1);
1002 init_waitqueue(&ip->i_wait);
1006 #if defined(AFS_LINUX24_ENV)
1008 ip->i_mapping = mapping;
1009 #ifdef STRUCT_ADDRESS_SPACE_HAS_GFP_MASK
1010 ip->i_data.gfp_mask = GFP_HIGHUSER;
1012 #if defined(AFS_LINUX26_ENV)
1013 mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
1015 extern struct backing_dev_info afs_backing_dev_info;
1017 mapping->backing_dev_info = &afs_backing_dev_info;
1022 #if !defined(AFS_LINUX26_ENV)
1024 ip->i_dev = afs_globalVFS->s_dev;
1026 ip->i_sb = afs_globalVFS;
1027 put_inode_on_dummy_list(ip);
1032 /* Hold it for the LRU (should make count 2) */
1033 VN_HOLD(AFSTOV(tvc));
1034 #else /* AFS_OSF_ENV */
1035 #if !defined(AFS_XBSD_ENV)
1036 VREFCOUNT_SET(tvc, 1); /* us */
1037 #endif /* AFS_XBSD_ENV */
1038 #endif /* AFS_OSF_ENV */
1039 #ifdef AFS_AIX32_ENV
1040 LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
1041 tvc->vmh = tvc->segid = NULL;
1044 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1045 #if defined(AFS_SUN5_ENV)
1046 rw_init(&tvc->rwlock, "vcache rwlock", RW_DEFAULT, NULL);
1048 #if defined(AFS_SUN55_ENV)
1049 /* This is required if the kaio (kernel aynchronous io)
1050 ** module is installed. Inside the kernel, the function
1051 ** check_vp( common/os/aio.c) checks to see if the kernel has
1052 ** to provide asynchronous io for this vnode. This
1053 ** function extracts the device number by following the
1054 ** v_data field of the vnode. If we do not set this field
1055 ** then the system panics. The value of the v_data field
1056 ** is not really important for AFS vnodes because the kernel
1057 ** does not do asynchronous io for regular files. Hence,
1058 ** for the time being, we fill up the v_data field with the
1059 ** vnode pointer itself. */
1060 tvc->v.v_data = (char *)tvc;
1061 #endif /* AFS_SUN55_ENV */
1063 afs_BozonInit(&tvc->pvnLock, tvc);
1067 tvc->callback = serverp; /* to minimize chance that clear
1068 * request is lost */
1069 /* initialize vnode data, note vrefCount is v.v_count */
1071 /* Don't forget to free the gnode space */
1072 tvc->v.v_gnode = gnodepnt =
1073 (struct gnode *)osi_AllocSmallSpace(sizeof(struct gnode));
1074 memset((char *)gnodepnt, 0, sizeof(struct gnode));
1076 #ifdef AFS_SGI64_ENV
1077 memset((void *)&(tvc->vc_bhv_desc), 0, sizeof(tvc->vc_bhv_desc));
1078 bhv_desc_init(&(tvc->vc_bhv_desc), tvc, tvc, &Afs_vnodeops);
1079 #ifdef AFS_SGI65_ENV
1080 vn_bhv_head_init(&(tvc->v.v_bh), "afsvp");
1081 vn_bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1083 bhv_head_init(&(tvc->v.v_bh));
1084 bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1086 #ifdef AFS_SGI65_ENV
1087 tvc->v.v_mreg = tvc->v.v_mregb = (struct pregion *)tvc;
1088 #ifdef VNODE_TRACING
1089 tvc->v.v_trace = ktrace_alloc(VNODE_TRACE_SIZE, 0);
1091 init_bitlock(&tvc->v.v_pcacheflag, VNODE_PCACHE_LOCKBIT, "afs_pcache",
1093 init_mutex(&tvc->v.v_filocksem, MUTEX_DEFAULT, "afsvfl", (long)tvc);
1094 init_mutex(&tvc->v.v_buf_lock, MUTEX_DEFAULT, "afsvnbuf", (long)tvc);
1096 vnode_pcache_init(&tvc->v);
1097 #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
1098 /* Above define is never true execpt in SGI test kernels. */
1099 init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number);
1101 #ifdef INTR_KTHREADS
1102 AFS_VN_INIT_BUF_LOCK(&(tvc->v));
1105 SetAfsVnode(AFSTOV(tvc));
1106 #endif /* AFS_SGI64_ENV */
1107 #ifdef AFS_DARWIN_ENV
1108 tvc->v.v_ubcinfo = UBC_INFO_NULL;
1109 lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
1110 cache_purge(AFSTOV(tvc));
1111 tvc->v.v_data = tvc;
1112 tvc->v.v_tag = VT_AFS;
1113 /* VLISTNONE(&tvc->v); */
1114 tvc->v.v_freelist.tqe_next = 0;
1115 tvc->v.v_freelist.tqe_prev = (struct vnode **)0xdeadb;
1116 /*tvc->vrefCount++; */
1119 * The proper value for mvstat (for root fids) is setup by the caller.
1122 if (afid->Fid.Vnode == 1 && afid->Fid.Unique == 1)
1124 if (afs_globalVFS == 0)
1125 osi_Panic("afs globalvfs");
1126 vSetVfsp(tvc, afs_globalVFS);
1127 vSetType(tvc, VREG);
1129 tvc->v.v_vfsnext = afs_globalVFS->vfs_vnodes; /* link off vfs */
1130 tvc->v.v_vfsprev = NULL;
1131 afs_globalVFS->vfs_vnodes = &tvc->v;
1132 if (tvc->v.v_vfsnext != NULL)
1133 tvc->v.v_vfsnext->v_vfsprev = &tvc->v;
1134 tvc->v.v_next = gnodepnt->gn_vnode; /*Single vnode per gnode for us! */
1135 gnodepnt->gn_vnode = &tvc->v;
1138 tvc->v.g_dev = ((struct mount *)afs_globalVFS->vfs_data)->m_dev;
1140 #if defined(AFS_DUX40_ENV)
1141 insmntque(tvc, afs_globalVFS, &afs_ubcops);
1144 /* Is this needed??? */
1145 insmntque(tvc, afs_globalVFS);
1146 #endif /* AFS_OSF_ENV */
1147 #endif /* AFS_DUX40_ENV */
1148 #if defined(AFS_SGI_ENV)
1149 VN_SET_DPAGES(&(tvc->v), (struct pfdat *)NULL);
1150 osi_Assert((tvc->v.v_flag & VINACT) == 0);
1152 osi_Assert(VN_GET_PGCNT(&(tvc->v)) == 0);
1153 osi_Assert(tvc->mapcnt == 0 && tvc->vc_locktrips == 0);
1154 osi_Assert(tvc->vc_rwlockid == OSI_NO_LOCKID);
1155 osi_Assert(tvc->v.v_filocks == NULL);
1156 #if !defined(AFS_SGI65_ENV)
1157 osi_Assert(tvc->v.v_filocksem == NULL);
1159 osi_Assert(tvc->cred == NULL);
1160 #ifdef AFS_SGI64_ENV
1161 vnode_pcache_reinit(&tvc->v);
1162 tvc->v.v_rdev = NODEV;
1164 vn_initlist((struct vnlist *)&tvc->v);
1166 #endif /* AFS_SGI_ENV */
1168 osi_dnlc_purgedp(tvc); /* this may be overkill */
1169 memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
1170 memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
1174 tvc->hnext = afs_vhashT[i];
1175 afs_vhashT[i] = tvc;
1176 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1177 refpanic("NewVCache VLRU inconsistent");
1179 QAdd(&VLRU, &tvc->vlruq); /* put in lruq */
1180 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1181 refpanic("NewVCache VLRU inconsistent2");
1183 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
1184 refpanic("NewVCache VLRU inconsistent3");
1186 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
1187 refpanic("NewVCache VLRU inconsistent4");
1193 } /*afs_NewVCache */
1197 * afs_FlushActiveVcaches
1203 * doflocks : Do we handle flocks?
1205 /* LOCK: afs_FlushActiveVcaches afs_xvcache N */
1207 afs_FlushActiveVcaches(register afs_int32 doflocks)
1209 register struct vcache *tvc;
1211 register struct conn *tc;
1212 register afs_int32 code;
1213 register struct AFS_UCRED *cred = NULL;
1214 struct vrequest treq, ureq;
1215 struct AFSVolSync tsync;
1217 XSTATS_DECLS AFS_STATCNT(afs_FlushActiveVcaches);
1218 ObtainReadLock(&afs_xvcache);
1219 for (i = 0; i < VCSIZE; i++) {
1220 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1221 if (doflocks && tvc->flockCount != 0) {
1222 /* if this entry has an flock, send a keep-alive call out */
1224 ReleaseReadLock(&afs_xvcache);
1225 ObtainWriteLock(&tvc->lock, 51);
1227 afs_InitReq(&treq, afs_osi_credp);
1228 treq.flags |= O_NONBLOCK;
1230 tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
1232 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
1235 RXAFS_ExtendLock(tc->id,
1236 (struct AFSFid *)&tvc->fid.Fid,
1242 } while (afs_Analyze
1243 (tc, code, &tvc->fid, &treq,
1244 AFS_STATS_FS_RPCIDX_EXTENDLOCK, SHARED_LOCK, NULL));
1246 ReleaseWriteLock(&tvc->lock);
1247 ObtainReadLock(&afs_xvcache);
1251 if ((tvc->states & CCore) || (tvc->states & CUnlinkedDel)) {
1253 * Don't let it evaporate in case someone else is in
1254 * this code. Also, drop the afs_xvcache lock while
1255 * getting vcache locks.
1258 ReleaseReadLock(&afs_xvcache);
1259 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1260 afs_BozonLock(&tvc->pvnLock, tvc);
1262 #if defined(AFS_SGI_ENV)
1264 * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
1266 osi_Assert(VREFCOUNT(tvc) > 0);
1267 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1269 ObtainWriteLock(&tvc->lock, 52);
1270 if (tvc->states & CCore) {
1271 tvc->states &= ~CCore;
1272 /* XXXX Find better place-holder for cred XXXX */
1273 cred = (struct AFS_UCRED *)tvc->linkData;
1274 tvc->linkData = NULL; /* XXX */
1275 afs_InitReq(&ureq, cred);
1276 afs_Trace2(afs_iclSetp, CM_TRACE_ACTCCORE,
1277 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32,
1278 tvc->execsOrWriters);
1279 code = afs_StoreOnLastReference(tvc, &ureq);
1280 ReleaseWriteLock(&tvc->lock);
1281 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1282 afs_BozonUnlock(&tvc->pvnLock, tvc);
1284 hzero(tvc->flushDV);
1287 if (code && code != VNOVNODE) {
1288 afs_StoreWarn(code, tvc->fid.Fid.Volume,
1289 /* /dev/console */ 1);
1291 } else if (tvc->states & CUnlinkedDel) {
1295 ReleaseWriteLock(&tvc->lock);
1296 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1297 afs_BozonUnlock(&tvc->pvnLock, tvc);
1299 #if defined(AFS_SGI_ENV)
1300 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1302 afs_remunlink(tvc, 0);
1303 #if defined(AFS_SGI_ENV)
1304 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1307 /* lost (or won, perhaps) the race condition */
1308 ReleaseWriteLock(&tvc->lock);
1309 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1310 afs_BozonUnlock(&tvc->pvnLock, tvc);
1313 #if defined(AFS_SGI_ENV)
1314 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1316 ObtainReadLock(&afs_xvcache);
1322 AFS_RELE(AFSTOV(tvc));
1324 /* Matches write code setting CCore flag */
1328 #ifdef AFS_DARWIN_ENV
1329 if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
1331 panic("flushactive open, hasubc, but refcnt 1");
1332 osi_VM_TryReclaim(tvc, 0);
1337 ReleaseReadLock(&afs_xvcache);
1345 * Make sure a cache entry is up-to-date status-wise.
1347 * NOTE: everywhere that calls this can potentially be sped up
1348 * by checking CStatd first, and avoiding doing the InitReq
1349 * if this is up-to-date.
1351 * Anymore, the only places that call this KNOW already that the
1352 * vcache is not up-to-date, so we don't screw around.
1355 * avc : Ptr to vcache entry to verify.
1360 afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq)
1362 register struct vcache *tvc;
1364 AFS_STATCNT(afs_VerifyVCache);
1366 #if defined(AFS_OSF_ENV)
1367 ObtainReadLock(&avc->lock);
1368 if (afs_IsWired(avc)) {
1369 ReleaseReadLock(&avc->lock);
1372 ReleaseReadLock(&avc->lock);
1373 #endif /* AFS_OSF_ENV */
1374 /* otherwise we must fetch the status info */
1376 ObtainWriteLock(&avc->lock, 53);
1377 if (avc->states & CStatd) {
1378 ReleaseWriteLock(&avc->lock);
1381 ObtainWriteLock(&afs_xcbhash, 461);
1382 avc->states &= ~(CStatd | CUnique);
1383 avc->callback = NULL;
1384 afs_DequeueCallback(avc);
1385 ReleaseWriteLock(&afs_xcbhash);
1386 ReleaseWriteLock(&avc->lock);
1388 /* since we've been called back, or the callback has expired,
1389 * it's possible that the contents of this directory, or this
1390 * file's name have changed, thus invalidating the dnlc contents.
1392 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1393 osi_dnlc_purgedp(avc);
1395 osi_dnlc_purgevp(avc);
1397 /* fetch the status info */
1398 tvc = afs_GetVCache(&avc->fid, areq, NULL, avc);
1401 /* Put it back; caller has already incremented vrefCount */
1405 } /*afs_VerifyVCache */
1412 * Simple copy of stat info into cache.
1415 * avc : Ptr to vcache entry involved.
1416 * astat : Ptr to stat info to copy.
1419 * Nothing interesting.
1421 * Callers: as of 1992-04-29, only called by WriteVCache
1424 afs_SimpleVStat(register struct vcache *avc,
1425 register struct AFSFetchStatus *astat, struct vrequest *areq)
1428 AFS_STATCNT(afs_SimpleVStat);
1431 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1432 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1434 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1436 #ifdef AFS_64BIT_CLIENT
1437 FillInt64(length, astat->Length_hi, astat->Length);
1438 #else /* AFS_64BIT_CLIENT */
1439 length = astat->Length;
1440 #endif /* AFS_64BIT_CLIENT */
1441 #if defined(AFS_SGI_ENV)
1442 osi_Assert((valusema(&avc->vc_rwlock) <= 0)
1443 && (OSI_GET_LOCKID() == avc->vc_rwlockid));
1444 if (length < avc->m.Length) {
1445 vnode_t *vp = (vnode_t *) avc;
1447 osi_Assert(WriteLocked(&avc->lock));
1448 ReleaseWriteLock(&avc->lock);
1450 PTOSSVP(vp, (off_t) length, (off_t) MAXLONG);
1452 ObtainWriteLock(&avc->lock, 67);
1455 /* if writing the file, don't fetch over this value */
1456 afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT, ICL_TYPE_POINTER, avc,
1457 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1458 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1459 avc->m.Length = length;
1460 avc->m.Date = astat->ClientModTime;
1462 avc->m.Owner = astat->Owner;
1463 avc->m.Group = astat->Group;
1464 avc->m.Mode = astat->UnixModeBits;
1465 if (vType(avc) == VREG) {
1466 avc->m.Mode |= S_IFREG;
1467 } else if (vType(avc) == VDIR) {
1468 avc->m.Mode |= S_IFDIR;
1469 } else if (vType(avc) == VLNK) {
1470 avc->m.Mode |= S_IFLNK;
1471 if ((avc->m.Mode & 0111) == 0)
1474 if (avc->states & CForeign) {
1475 struct axscache *ac;
1476 avc->anyAccess = astat->AnonymousAccess;
1478 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1480 * Caller has at least one bit not covered by anonymous, and
1481 * thus may have interesting rights.
1483 * HOWEVER, this is a really bad idea, because any access query
1484 * for bits which aren't covered by anonymous, on behalf of a user
1485 * who doesn't have any special rights, will result in an answer of
1486 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1487 * It's an especially bad idea under Ultrix, since (due to the lack of
1488 * a proper access() call) it must perform several afs_access() calls
1489 * in order to create magic mode bits that vary according to who makes
1490 * the call. In other words, _every_ stat() generates a test for
1493 #endif /* badidea */
1494 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1495 ac->axess = astat->CallerAccess;
1496 else /* not found, add a new one if possible */
1497 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1501 } /*afs_SimpleVStat */
1508 * Store the status info *only* back to the server for a
1512 * avc : Ptr to the vcache entry.
1513 * astatus : Ptr to the status info to store.
1514 * areq : Ptr to the associated vrequest.
1517 * Must be called with a shared lock held on the vnode.
1521 afs_WriteVCache(register struct vcache *avc,
1522 register struct AFSStoreStatus *astatus,
1523 struct vrequest *areq)
1527 struct AFSFetchStatus OutStatus;
1528 struct AFSVolSync tsync;
1529 XSTATS_DECLS AFS_STATCNT(afs_WriteVCache);
1530 afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
1531 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
1534 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1536 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
1539 RXAFS_StoreStatus(tc->id, (struct AFSFid *)&avc->fid.Fid,
1540 astatus, &OutStatus, &tsync);
1545 } while (afs_Analyze
1546 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STORESTATUS,
1547 SHARED_LOCK, NULL));
1549 UpgradeSToWLock(&avc->lock, 20);
1551 /* success, do the changes locally */
1552 afs_SimpleVStat(avc, &OutStatus, areq);
1554 * Update the date, too. SimpleVStat didn't do this, since
1555 * it thought we were doing this after fetching new status
1556 * over a file being written.
1558 avc->m.Date = OutStatus.ClientModTime;
1560 /* failure, set up to check with server next time */
1561 ObtainWriteLock(&afs_xcbhash, 462);
1562 afs_DequeueCallback(avc);
1563 avc->states &= ~(CStatd | CUnique); /* turn off stat valid flag */
1564 ReleaseWriteLock(&afs_xcbhash);
1565 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1566 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
1568 ConvertWToSLock(&avc->lock);
1571 } /*afs_WriteVCache */
1577 * Copy astat block into vcache info
1580 * avc : Ptr to vcache entry.
1581 * astat : Ptr to stat block to copy in.
1582 * areq : Ptr to associated request.
1585 * Must be called under a write lock
1587 * Note: this code may get dataversion and length out of sync if the file has
1588 * been modified. This is less than ideal. I haven't thought about
1589 * it sufficiently to be certain that it is adequate.
1592 afs_ProcessFS(register struct vcache *avc,
1593 register struct AFSFetchStatus *astat, struct vrequest *areq)
1596 AFS_STATCNT(afs_ProcessFS);
1598 #ifdef AFS_64BIT_CLIENT
1599 FillInt64(length, astat->Length_hi, astat->Length);
1600 #else /* AFS_64BIT_CLIENT */
1601 length = astat->Length;
1602 #endif /* AFS_64BIT_CLIENT */
1603 /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
1604 * number for each bulk status request. Under no circumstances
1605 * should afs_DoBulkStat store a sequence number if the new
1606 * length will be ignored when afs_ProcessFS is called with
1607 * new stats. If you change the following conditional then you
1608 * also need to change the conditional in afs_DoBulkStat. */
1610 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1611 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1613 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1615 /* if we're writing or mapping this file, don't fetch over these
1618 afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
1619 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1620 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1621 avc->m.Length = length;
1622 avc->m.Date = astat->ClientModTime;
1624 hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
1625 avc->m.Owner = astat->Owner;
1626 avc->m.Mode = astat->UnixModeBits;
1627 avc->m.Group = astat->Group;
1628 avc->m.LinkCount = astat->LinkCount;
1629 if (astat->FileType == File) {
1630 vSetType(avc, VREG);
1631 avc->m.Mode |= S_IFREG;
1632 } else if (astat->FileType == Directory) {
1633 vSetType(avc, VDIR);
1634 avc->m.Mode |= S_IFDIR;
1635 } else if (astat->FileType == SymbolicLink) {
1636 if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
1637 vSetType(avc, VDIR);
1638 avc->m.Mode |= S_IFDIR;
1640 vSetType(avc, VLNK);
1641 avc->m.Mode |= S_IFLNK;
1643 if ((avc->m.Mode & 0111) == 0) {
1647 avc->anyAccess = astat->AnonymousAccess;
1649 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1651 * Caller has at least one bit not covered by anonymous, and
1652 * thus may have interesting rights.
1654 * HOWEVER, this is a really bad idea, because any access query
1655 * for bits which aren't covered by anonymous, on behalf of a user
1656 * who doesn't have any special rights, will result in an answer of
1657 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1658 * It's an especially bad idea under Ultrix, since (due to the lack of
1659 * a proper access() call) it must perform several afs_access() calls
1660 * in order to create magic mode bits that vary according to who makes
1661 * the call. In other words, _every_ stat() generates a test for
1664 #endif /* badidea */
1666 struct axscache *ac;
1667 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1668 ac->axess = astat->CallerAccess;
1669 else /* not found, add a new one if possible */
1670 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1672 #ifdef AFS_LINUX22_ENV
1673 vcache2inode(avc); /* Set the inode attr cache */
1675 #ifdef AFS_DARWIN_ENV
1676 osi_VM_Setup(avc, 1);
1679 } /*afs_ProcessFS */
1683 afs_RemoteLookup(register struct VenusFid *afid, struct vrequest *areq,
1684 char *name, struct VenusFid *nfid,
1685 struct AFSFetchStatus *OutStatusp,
1686 struct AFSCallBack *CallBackp, struct server **serverp,
1687 struct AFSVolSync *tsyncp)
1691 register struct conn *tc;
1692 struct AFSFetchStatus OutDirStatus;
1693 XSTATS_DECLS if (!name)
1694 name = ""; /* XXX */
1696 tc = afs_Conn(afid, areq, SHARED_LOCK);
1699 *serverp = tc->srvr->server;
1701 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
1704 RXAFS_Lookup(tc->id, (struct AFSFid *)&afid->Fid, name,
1705 (struct AFSFid *)&nfid->Fid, OutStatusp,
1706 &OutDirStatus, CallBackp, tsyncp);
1711 } while (afs_Analyze
1712 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_XLOOKUP, SHARED_LOCK,
1723 * Given a file id and a vrequest structure, fetch the status
1724 * information associated with the file.
1728 * areq : Ptr to associated vrequest structure, specifying the
1729 * user whose authentication tokens will be used.
1730 * avc : caller may already have a vcache for this file, which is
1734 * The cache entry is returned with an increased vrefCount field.
1735 * The entry must be discarded by calling afs_PutVCache when you
1736 * are through using the pointer to the cache entry.
1738 * You should not hold any locks when calling this function, except
1739 * locks on other vcache entries. If you lock more than one vcache
1740 * entry simultaneously, you should lock them in this order:
1742 * 1. Lock all files first, then directories.
1743 * 2. Within a particular type, lock entries in Fid.Vnode order.
1745 * This locking hierarchy is convenient because it allows locking
1746 * of a parent dir cache entry, given a file (to check its access
1747 * control list). It also allows renames to be handled easily by
1748 * locking directories in a constant order.
1749 * NB. NewVCache -> FlushVCache presently (4/10/95) drops the xvcache lock.
1751 /* might have a vcache structure already, which must
1752 * already be held by the caller */
1755 afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
1756 afs_int32 * cached, struct vcache *avc)
1759 afs_int32 code, newvcache = 0;
1760 register struct vcache *tvc;
1764 AFS_STATCNT(afs_GetVCache);
1767 *cached = 0; /* Init just in case */
1769 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1773 ObtainSharedLock(&afs_xvcache, 5);
1775 tvc = afs_FindVCache(afid, &retry, DO_STATS | DO_VLRU);
1777 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1778 ReleaseSharedLock(&afs_xvcache);
1779 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1787 if (tvc->states & CStatd) {
1788 ReleaseSharedLock(&afs_xvcache);
1792 UpgradeSToWLock(&afs_xvcache, 21);
1794 /* no cache entry, better grab one */
1795 tvc = afs_NewVCache(afid, NULL);
1798 ConvertWToSLock(&afs_xvcache);
1799 afs_stats_cmperf.vcacheMisses++;
1802 ReleaseSharedLock(&afs_xvcache);
1804 ObtainWriteLock(&tvc->lock, 54);
1806 if (tvc->states & CStatd) {
1807 #ifdef AFS_LINUX22_ENV
1810 ReleaseWriteLock(&tvc->lock);
1811 #ifdef AFS_DARWIN_ENV
1812 osi_VM_Setup(tvc, 0);
1816 #if defined(AFS_OSF_ENV)
1817 if (afs_IsWired(tvc)) {
1818 ReleaseWriteLock(&tvc->lock);
1821 #endif /* AFS_OSF_ENV */
1823 VOP_LOCK(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY, curproc);
1824 uvm_vnp_uncache(AFSTOV(tvc));
1825 VOP_UNLOCK(AFSTOV(tvc), 0, curproc);
1829 * XXX - I really don't like this. Should try to understand better.
1830 * It seems that sometimes, when we get called, we already hold the
1831 * lock on the vnode (e.g., from afs_getattr via afs_VerifyVCache).
1832 * We can't drop the vnode lock, because that could result in a race.
1833 * Sometimes, though, we get here and don't hold the vnode lock.
1834 * I hate code paths that sometimes hold locks and sometimes don't.
1835 * In any event, the dodge we use here is to check whether the vnode
1836 * is locked, and if it isn't, then we gain and drop it around the call
1837 * to vinvalbuf; otherwise, we leave it alone.
1844 #ifdef AFS_FBSD50_ENV
1845 iheldthelock = VOP_ISLOCKED(vp, curthread);
1847 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
1848 vinvalbuf(vp, V_SAVE, osi_curcred(), curthread, PINOD, 0);
1850 VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
1852 iheldthelock = VOP_ISLOCKED(vp, curproc);
1854 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
1855 vinvalbuf(vp, V_SAVE, osi_curcred(), curproc, PINOD, 0);
1857 VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
1862 ObtainWriteLock(&afs_xcbhash, 464);
1863 tvc->states &= ~CUnique;
1865 afs_DequeueCallback(tvc);
1866 ReleaseWriteLock(&afs_xcbhash);
1868 /* It is always appropriate to throw away all the access rights? */
1869 afs_FreeAllAxs(&(tvc->Access));
1870 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-volume info */
1872 if ((tvp->states & VForeign)) {
1874 tvc->states |= CForeign;
1875 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
1876 && (tvp->rootUnique == afid->Fid.Unique)) {
1880 if (tvp->states & VRO)
1882 if (tvp->states & VBackup)
1883 tvc->states |= CBackup;
1884 /* now copy ".." entry back out of volume structure, if necessary */
1885 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
1887 tvc->mvid = (struct VenusFid *)
1888 osi_AllocSmallSpace(sizeof(struct VenusFid));
1889 *tvc->mvid = tvp->dotdot;
1891 afs_PutVolume(tvp, READ_LOCK);
1895 afs_RemoveVCB(afid);
1897 struct AFSFetchStatus OutStatus;
1899 if (afs_DynrootNewVnode(tvc, &OutStatus)) {
1900 afs_ProcessFS(tvc, &OutStatus, areq);
1901 tvc->states |= CStatd | CUnique;
1904 code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
1909 ReleaseWriteLock(&tvc->lock);
1911 ObtainReadLock(&afs_xvcache);
1913 ReleaseReadLock(&afs_xvcache);
1917 ReleaseWriteLock(&tvc->lock);
1920 } /*afs_GetVCache */
1925 afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
1926 afs_int32 * cached, struct vcache *adp, char *aname)
1928 afs_int32 code, now, newvcache = 0;
1929 struct VenusFid nfid;
1930 register struct vcache *tvc;
1932 struct AFSFetchStatus OutStatus;
1933 struct AFSCallBack CallBack;
1934 struct AFSVolSync tsync;
1935 struct server *serverp = 0;
1939 AFS_STATCNT(afs_GetVCache);
1941 *cached = 0; /* Init just in case */
1943 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1947 ObtainReadLock(&afs_xvcache);
1948 tvc = afs_FindVCache(afid, &retry, DO_STATS /* no vlru */ );
1951 ReleaseReadLock(&afs_xvcache);
1953 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1954 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1958 ObtainReadLock(&tvc->lock);
1960 if (tvc->states & CStatd) {
1964 ReleaseReadLock(&tvc->lock);
1967 tvc->states &= ~CUnique;
1969 ReleaseReadLock(&tvc->lock);
1970 ObtainReadLock(&afs_xvcache);
1974 ReleaseReadLock(&afs_xvcache);
1976 /* lookup the file */
1979 origCBs = afs_allCBs; /* if anything changes, we don't have a cb */
1981 afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
1984 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1988 ObtainSharedLock(&afs_xvcache, 6);
1989 tvc = afs_FindVCache(&nfid, &retry, DO_VLRU /* no xstats now */ );
1991 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1992 ReleaseSharedLock(&afs_xvcache);
1993 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1999 /* no cache entry, better grab one */
2000 UpgradeSToWLock(&afs_xvcache, 22);
2001 tvc = afs_NewVCache(&nfid, serverp);
2003 ConvertWToSLock(&afs_xvcache);
2006 ReleaseSharedLock(&afs_xvcache);
2007 ObtainWriteLock(&tvc->lock, 55);
2009 /* It is always appropriate to throw away all the access rights? */
2010 afs_FreeAllAxs(&(tvc->Access));
2011 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-vol info */
2013 if ((tvp->states & VForeign)) {
2015 tvc->states |= CForeign;
2016 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
2017 && (tvp->rootUnique == afid->Fid.Unique))
2020 if (tvp->states & VRO)
2022 if (tvp->states & VBackup)
2023 tvc->states |= CBackup;
2024 /* now copy ".." entry back out of volume structure, if necessary */
2025 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2027 tvc->mvid = (struct VenusFid *)
2028 osi_AllocSmallSpace(sizeof(struct VenusFid));
2029 *tvc->mvid = tvp->dotdot;
2034 ObtainWriteLock(&afs_xcbhash, 465);
2035 afs_DequeueCallback(tvc);
2036 tvc->states &= ~(CStatd | CUnique);
2037 ReleaseWriteLock(&afs_xcbhash);
2038 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2039 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2041 afs_PutVolume(tvp, READ_LOCK);
2042 ReleaseWriteLock(&tvc->lock);
2043 ObtainReadLock(&afs_xvcache);
2045 ReleaseReadLock(&afs_xvcache);
2049 ObtainWriteLock(&afs_xcbhash, 466);
2050 if (origCBs == afs_allCBs) {
2051 if (CallBack.ExpirationTime) {
2052 tvc->callback = serverp;
2053 tvc->cbExpires = CallBack.ExpirationTime + now;
2054 tvc->states |= CStatd | CUnique;
2055 tvc->states &= ~CBulkFetching;
2056 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvp);
2057 } else if (tvc->states & CRO) {
2058 /* adapt gives us an hour. */
2059 tvc->cbExpires = 3600 + osi_Time();
2060 /*XXX*/ tvc->states |= CStatd | CUnique;
2061 tvc->states &= ~CBulkFetching;
2062 afs_QueueCallback(tvc, CBHash(3600), tvp);
2064 tvc->callback = NULL;
2065 afs_DequeueCallback(tvc);
2066 tvc->states &= ~(CStatd | CUnique);
2067 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2068 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2071 afs_DequeueCallback(tvc);
2072 tvc->states &= ~CStatd;
2073 tvc->states &= ~CUnique;
2074 tvc->callback = NULL;
2075 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2076 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2078 ReleaseWriteLock(&afs_xcbhash);
2080 afs_PutVolume(tvp, READ_LOCK);
2081 afs_ProcessFS(tvc, &OutStatus, areq);
2083 ReleaseWriteLock(&tvc->lock);
2089 afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
2090 afs_int32 * cached, struct volume *tvolp)
2092 afs_int32 code = 0, i, newvcache = 0, haveStatus = 0;
2093 afs_int32 getNewFid = 0;
2095 struct VenusFid nfid;
2096 register struct vcache *tvc;
2097 struct server *serverp = 0;
2098 struct AFSFetchStatus OutStatus;
2099 struct AFSCallBack CallBack;
2100 struct AFSVolSync tsync;
2106 if (!tvolp->rootVnode || getNewFid) {
2107 struct VenusFid tfid;
2110 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2111 origCBs = afs_allCBs; /* ignore InitCallBackState */
2113 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2118 /* ReleaseReadLock(&tvolp->lock); */
2119 ObtainWriteLock(&tvolp->lock, 56);
2120 tvolp->rootVnode = afid->Fid.Vnode = nfid.Fid.Vnode;
2121 tvolp->rootUnique = afid->Fid.Unique = nfid.Fid.Unique;
2122 ReleaseWriteLock(&tvolp->lock);
2123 /* ObtainReadLock(&tvolp->lock);*/
2126 afid->Fid.Vnode = tvolp->rootVnode;
2127 afid->Fid.Unique = tvolp->rootUnique;
2130 ObtainSharedLock(&afs_xvcache, 7);
2132 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2133 if (!FidCmp(&(tvc->fid), afid)) {
2135 /* Grab this vnode, possibly reactivating from the free list */
2136 /* for the present (95.05.25) everything on the hash table is
2137 * definitively NOT in the free list -- at least until afs_reclaim
2138 * can be safely implemented */
2141 vg = vget(AFSTOV(tvc)); /* this bumps ref count */
2145 #endif /* AFS_OSF_ENV */
2150 if (!haveStatus && (!tvc || !(tvc->states & CStatd))) {
2151 /* Mount point no longer stat'd or unknown. FID may have changed. */
2154 AFS_RELE(AFSTOV(tvc));
2158 ReleaseSharedLock(&afs_xvcache);
2163 UpgradeSToWLock(&afs_xvcache, 23);
2164 /* no cache entry, better grab one */
2165 tvc = afs_NewVCache(afid, NULL);
2167 afs_stats_cmperf.vcacheMisses++;
2171 afs_stats_cmperf.vcacheHits++;
2173 /* we already bumped the ref count in the for loop above */
2174 #else /* AFS_OSF_ENV */
2177 UpgradeSToWLock(&afs_xvcache, 24);
2178 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2179 refpanic("GRVC VLRU inconsistent0");
2181 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2182 refpanic("GRVC VLRU inconsistent1");
2184 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2185 refpanic("GRVC VLRU inconsistent2");
2187 QRemove(&tvc->vlruq); /* move to lruq head */
2188 QAdd(&VLRU, &tvc->vlruq);
2189 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2190 refpanic("GRVC VLRU inconsistent3");
2192 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2193 refpanic("GRVC VLRU inconsistent4");
2195 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2196 refpanic("GRVC VLRU inconsistent5");
2201 ReleaseWriteLock(&afs_xvcache);
2203 if (tvc->states & CStatd) {
2207 ObtainReadLock(&tvc->lock);
2208 tvc->states &= ~CUnique;
2209 tvc->callback = NULL; /* redundant, perhaps */
2210 ReleaseReadLock(&tvc->lock);
2213 ObtainWriteLock(&tvc->lock, 57);
2215 /* It is always appropriate to throw away all the access rights? */
2216 afs_FreeAllAxs(&(tvc->Access));
2219 tvc->states |= CForeign;
2220 if (tvolp->states & VRO)
2222 if (tvolp->states & VBackup)
2223 tvc->states |= CBackup;
2224 /* now copy ".." entry back out of volume structure, if necessary */
2225 if (newvcache && (tvolp->rootVnode == afid->Fid.Vnode)
2226 && (tvolp->rootUnique == afid->Fid.Unique)) {
2229 if (tvc->mvstat == 2 && tvolp->dotdot.Fid.Volume != 0) {
2231 tvc->mvid = (struct VenusFid *)
2232 osi_AllocSmallSpace(sizeof(struct VenusFid));
2233 *tvc->mvid = tvolp->dotdot;
2237 afs_RemoveVCB(afid);
2240 struct VenusFid tfid;
2243 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2244 origCBs = afs_allCBs; /* ignore InitCallBackState */
2246 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2251 ObtainWriteLock(&afs_xcbhash, 467);
2252 afs_DequeueCallback(tvc);
2253 tvc->callback = NULL;
2254 tvc->states &= ~(CStatd | CUnique);
2255 ReleaseWriteLock(&afs_xcbhash);
2256 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2257 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2258 ReleaseWriteLock(&tvc->lock);
2259 ObtainReadLock(&afs_xvcache);
2261 ReleaseReadLock(&afs_xvcache);
2265 ObtainWriteLock(&afs_xcbhash, 468);
2266 if (origCBs == afs_allCBs) {
2267 tvc->states |= CTruth;
2268 tvc->callback = serverp;
2269 if (CallBack.ExpirationTime != 0) {
2270 tvc->cbExpires = CallBack.ExpirationTime + start;
2271 tvc->states |= CStatd;
2272 tvc->states &= ~CBulkFetching;
2273 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvolp);
2274 } else if (tvc->states & CRO) {
2275 /* adapt gives us an hour. */
2276 tvc->cbExpires = 3600 + osi_Time();
2277 /*XXX*/ tvc->states |= CStatd;
2278 tvc->states &= ~CBulkFetching;
2279 afs_QueueCallback(tvc, CBHash(3600), tvolp);
2282 afs_DequeueCallback(tvc);
2283 tvc->callback = NULL;
2284 tvc->states &= ~(CStatd | CUnique);
2285 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2286 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2288 ReleaseWriteLock(&afs_xcbhash);
2289 afs_ProcessFS(tvc, &OutStatus, areq);
2291 ReleaseWriteLock(&tvc->lock);
2298 * must be called with avc write-locked
2299 * don't absolutely have to invalidate the hint unless the dv has
2300 * changed, but be sure to get it right else there will be consistency bugs.
2303 afs_FetchStatus(struct vcache * avc, struct VenusFid * afid,
2304 struct vrequest * areq, struct AFSFetchStatus * Outsp)
2307 afs_uint32 start = 0;
2308 register struct conn *tc;
2309 struct AFSCallBack CallBack;
2310 struct AFSVolSync tsync;
2311 struct volume *volp;
2314 tc = afs_Conn(afid, areq, SHARED_LOCK);
2315 avc->quick.stamp = 0;
2316 avc->h1.dchint = NULL; /* invalidate hints */
2318 avc->callback = tc->srvr->server;
2320 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
2323 RXAFS_FetchStatus(tc->id, (struct AFSFid *)&afid->Fid, Outsp,
2331 } while (afs_Analyze
2332 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS,
2333 SHARED_LOCK, NULL));
2336 afs_ProcessFS(avc, Outsp, areq);
2337 volp = afs_GetVolume(afid, areq, READ_LOCK);
2338 ObtainWriteLock(&afs_xcbhash, 469);
2339 avc->states |= CTruth;
2340 if (avc->callback /* check for race */ ) {
2341 if (CallBack.ExpirationTime != 0) {
2342 avc->cbExpires = CallBack.ExpirationTime + start;
2343 avc->states |= CStatd;
2344 avc->states &= ~CBulkFetching;
2345 afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
2346 } else if (avc->states & CRO) { /* ordinary callback on a read-only volume -- AFS 3.2 style */
2347 avc->cbExpires = 3600 + start;
2348 avc->states |= CStatd;
2349 avc->states &= ~CBulkFetching;
2350 afs_QueueCallback(avc, CBHash(3600), volp);
2352 afs_DequeueCallback(avc);
2353 avc->callback = NULL;
2354 avc->states &= ~(CStatd | CUnique);
2355 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2356 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2359 afs_DequeueCallback(avc);
2360 avc->callback = NULL;
2361 avc->states &= ~(CStatd | CUnique);
2362 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2363 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2365 ReleaseWriteLock(&afs_xcbhash);
2367 afs_PutVolume(volp, READ_LOCK);
2369 /* used to undo the local callback, but that's too extreme.
2370 * There are plenty of good reasons that fetchstatus might return
2371 * an error, such as EPERM. If we have the vnode cached, statd,
2372 * with callback, might as well keep track of the fact that we
2373 * don't have access...
2375 if (code == EPERM || code == EACCES) {
2376 struct axscache *ac;
2377 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
2379 else /* not found, add a new one if possible */
2380 afs_AddAxs(avc->Access, areq->uid, 0);
2391 * Stuff some information into the vcache for the given file.
2394 * afid : File in question.
2395 * OutStatus : Fetch status on the file.
2396 * CallBack : Callback info.
2397 * tc : RPC connection involved.
2398 * areq : vrequest involved.
2401 * Nothing interesting.
2404 afs_StuffVcache(register struct VenusFid *afid,
2405 struct AFSFetchStatus *OutStatus,
2406 struct AFSCallBack *CallBack, register struct conn *tc,
2407 struct vrequest *areq)
2409 register afs_int32 code, i, newvcache = 0;
2410 register struct vcache *tvc;
2411 struct AFSVolSync tsync;
2413 struct axscache *ac;
2416 AFS_STATCNT(afs_StuffVcache);
2417 #ifdef IFS_VCACHECOUNT
2422 ObtainSharedLock(&afs_xvcache, 8);
2424 tvc = afs_FindVCache(afid, &retry, DO_VLRU /* no stats */ );
2426 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2427 ReleaseSharedLock(&afs_xvcache);
2428 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2434 /* no cache entry, better grab one */
2435 UpgradeSToWLock(&afs_xvcache, 25);
2436 tvc = afs_NewVCache(afid, NULL);
2438 ConvertWToSLock(&afs_xvcache);
2441 ReleaseSharedLock(&afs_xvcache);
2442 ObtainWriteLock(&tvc->lock, 58);
2444 tvc->states &= ~CStatd;
2445 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2446 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2448 /* Is it always appropriate to throw away all the access rights? */
2449 afs_FreeAllAxs(&(tvc->Access));
2451 /*Copy useful per-volume info */
2452 tvp = afs_GetVolume(afid, areq, READ_LOCK);
2454 if (newvcache && (tvp->states & VForeign))
2455 tvc->states |= CForeign;
2456 if (tvp->states & VRO)
2458 if (tvp->states & VBackup)
2459 tvc->states |= CBackup;
2461 * Now, copy ".." entry back out of volume structure, if
2464 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2466 tvc->mvid = (struct VenusFid *)
2467 osi_AllocSmallSpace(sizeof(struct VenusFid));
2468 *tvc->mvid = tvp->dotdot;
2471 /* store the stat on the file */
2472 afs_RemoveVCB(afid);
2473 afs_ProcessFS(tvc, OutStatus, areq);
2474 tvc->callback = tc->srvr->server;
2476 /* we use osi_Time twice below. Ideally, we would use the time at which
2477 * the FetchStatus call began, instead, but we don't have it here. So we
2478 * make do with "now". In the CRO case, it doesn't really matter. In
2479 * the other case, we hope that the difference between "now" and when the
2480 * call actually began execution on the server won't be larger than the
2481 * padding which the server keeps. Subtract 1 second anyway, to be on
2482 * the safe side. Can't subtract more because we don't know how big
2483 * ExpirationTime is. Possible consistency problems may arise if the call
2484 * timeout period becomes longer than the server's expiration padding. */
2485 ObtainWriteLock(&afs_xcbhash, 470);
2486 if (CallBack->ExpirationTime != 0) {
2487 tvc->cbExpires = CallBack->ExpirationTime + osi_Time() - 1;
2488 tvc->states |= CStatd;
2489 tvc->states &= ~CBulkFetching;
2490 afs_QueueCallback(tvc, CBHash(CallBack->ExpirationTime), tvp);
2491 } else if (tvc->states & CRO) {
2492 /* old-fashioned AFS 3.2 style */
2493 tvc->cbExpires = 3600 + osi_Time();
2494 /*XXX*/ tvc->states |= CStatd;
2495 tvc->states &= ~CBulkFetching;
2496 afs_QueueCallback(tvc, CBHash(3600), tvp);
2498 afs_DequeueCallback(tvc);
2499 tvc->callback = NULL;
2500 tvc->states &= ~(CStatd | CUnique);
2501 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2502 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2504 ReleaseWriteLock(&afs_xcbhash);
2506 afs_PutVolume(tvp, READ_LOCK);
2508 /* look in per-pag cache */
2509 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, areq->uid)))
2510 ac->axess = OutStatus->CallerAccess; /* substitute pags */
2511 else /* not found, add a new one if possible */
2512 afs_AddAxs(tvc->Access, areq->uid, OutStatus->CallerAccess);
2514 ReleaseWriteLock(&tvc->lock);
2515 afs_Trace4(afs_iclSetp, CM_TRACE_STUFFVCACHE, ICL_TYPE_POINTER, tvc,
2516 ICL_TYPE_POINTER, tvc->callback, ICL_TYPE_INT32,
2517 tvc->cbExpires, ICL_TYPE_INT32, tvc->cbExpires - osi_Time());
2519 * Release ref count... hope this guy stays around...
2522 } /*afs_StuffVcache */
2529 * Decrements the reference count on a cache entry.
2532 * avc : Pointer to the cache entry to decrement.
2535 * Nothing interesting.
2538 afs_PutVCache(register struct vcache *avc)
2540 AFS_STATCNT(afs_PutVCache);
2542 * Can we use a read lock here?
2544 ObtainReadLock(&afs_xvcache);
2546 ReleaseReadLock(&afs_xvcache);
2547 } /*afs_PutVCache */
2553 * Find a vcache entry given a fid.
2556 * afid : Pointer to the fid whose cache entry we desire.
2557 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2558 * unlock the vnode, and try again.
2559 * flags: bit 1 to specify whether to compute hit statistics. Not
2560 * set if FindVCache is called as part of internal bookkeeping.
2563 * Must be called with the afs_xvcache lock at least held at
2564 * the read level. In order to do the VLRU adjustment, the xvcache lock
2565 * must be shared-- we upgrade it here.
2569 afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, afs_int32 flag)
2572 register struct vcache *tvc;
2575 AFS_STATCNT(afs_FindVCache);
2578 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2579 if (FidMatches(afid, tvc)) {
2581 /* Grab this vnode, possibly reactivating from the free list */
2584 vg = vget(AFSTOV(tvc));
2588 #endif /* AFS_OSF_ENV */
2593 /* should I have a read lock on the vnode here? */
2597 #if !defined(AFS_OSF_ENV)
2598 osi_vnhold(tvc, retry); /* already held, above */
2599 if (retry && *retry)
2603 * only move to front of vlru if we have proper vcache locking)
2605 if (flag & DO_VLRU) {
2606 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2607 refpanic("FindVC VLRU inconsistent1");
2609 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2610 refpanic("FindVC VLRU inconsistent1");
2612 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2613 refpanic("FindVC VLRU inconsistent2");
2615 UpgradeSToWLock(&afs_xvcache, 26);
2616 QRemove(&tvc->vlruq);
2617 QAdd(&VLRU, &tvc->vlruq);
2618 ConvertWToSLock(&afs_xvcache);
2619 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2620 refpanic("FindVC VLRU inconsistent1");
2622 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2623 refpanic("FindVC VLRU inconsistent2");
2625 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2626 refpanic("FindVC VLRU inconsistent3");
2632 if (flag & DO_STATS) {
2634 afs_stats_cmperf.vcacheHits++;
2636 afs_stats_cmperf.vcacheMisses++;
2637 if (afs_IsPrimaryCellNum(afid->Cell))
2638 afs_stats_cmperf.vlocalAccesses++;
2640 afs_stats_cmperf.vremoteAccesses++;
2642 #ifdef AFS_LINUX22_ENV
2643 if (tvc && (tvc->states & CStatd))
2644 vcache2inode(tvc); /* mainly to reset i_nlink */
2646 #ifdef AFS_DARWIN_ENV
2648 osi_VM_Setup(tvc, 0);
2651 } /*afs_FindVCache */
2657 * Find a vcache entry given a fid. Does a wildcard match on what we
2658 * have for the fid. If more than one entry, don't return anything.
2661 * avcp : Fill in pointer if we found one and only one.
2662 * afid : Pointer to the fid whose cache entry we desire.
2663 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2664 * unlock the vnode, and try again.
2665 * flags: bit 1 to specify whether to compute hit statistics. Not
2666 * set if FindVCache is called as part of internal bookkeeping.
2669 * Must be called with the afs_xvcache lock at least held at
2670 * the read level. In order to do the VLRU adjustment, the xvcache lock
2671 * must be shared-- we upgrade it here.
2674 * number of matches found.
2677 int afs_duplicate_nfs_fids = 0;
2680 afs_NFSFindVCache(struct vcache **avcp, struct VenusFid *afid)
2682 register struct vcache *tvc;
2684 afs_int32 count = 0;
2685 struct vcache *found_tvc = NULL;
2687 AFS_STATCNT(afs_FindVCache);
2689 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2693 ObtainSharedLock(&afs_xvcache, 331);
2696 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2697 /* Match only on what we have.... */
2698 if (((tvc->fid.Fid.Vnode & 0xffff) == afid->Fid.Vnode)
2699 && (tvc->fid.Fid.Volume == afid->Fid.Volume)
2700 && ((tvc->fid.Fid.Unique & 0xffffff) == afid->Fid.Unique)
2701 && (tvc->fid.Cell == afid->Cell)) {
2703 /* Grab this vnode, possibly reactivating from the free list */
2706 vg = vget(AFSTOV(tvc));
2709 /* This vnode no longer exists. */
2712 #endif /* AFS_OSF_ENV */
2717 /* Drop our reference counts. */
2719 vrele(AFSTOV(found_tvc));
2721 afs_duplicate_nfs_fids++;
2722 ReleaseSharedLock(&afs_xvcache);
2730 /* should I have a read lock on the vnode here? */
2732 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2733 afs_int32 retry = 0;
2734 osi_vnhold(tvc, &retry);
2737 found_tvc = (struct vcache *)0;
2738 ReleaseSharedLock(&afs_xvcache);
2739 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2743 #if !defined(AFS_OSF_ENV)
2744 osi_vnhold(tvc, (int *)0); /* already held, above */
2748 * We obtained the xvcache lock above.
2750 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2751 refpanic("FindVC VLRU inconsistent1");
2753 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2754 refpanic("FindVC VLRU inconsistent1");
2756 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2757 refpanic("FindVC VLRU inconsistent2");
2759 UpgradeSToWLock(&afs_xvcache, 568);
2760 QRemove(&tvc->vlruq);
2761 QAdd(&VLRU, &tvc->vlruq);
2762 ConvertWToSLock(&afs_xvcache);
2763 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2764 refpanic("FindVC VLRU inconsistent1");
2766 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2767 refpanic("FindVC VLRU inconsistent2");
2769 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2770 refpanic("FindVC VLRU inconsistent3");
2776 afs_stats_cmperf.vcacheHits++;
2778 afs_stats_cmperf.vcacheMisses++;
2779 if (afs_IsPrimaryCellNum(afid->Cell))
2780 afs_stats_cmperf.vlocalAccesses++;
2782 afs_stats_cmperf.vremoteAccesses++;
2784 *avcp = tvc; /* May be null */
2786 ReleaseSharedLock(&afs_xvcache);
2787 return (tvc ? 1 : 0);
2789 } /*afs_NFSFindVCache */
2797 * Initialize vcache related variables
2800 afs_vcacheInit(int astatSize)
2802 register struct vcache *tvp;
2804 #if defined(AFS_OSF_ENV)
2805 if (!afs_maxvcount) {
2806 #if defined(AFS_OSF30_ENV)
2807 afs_maxvcount = max_vnodes / 2; /* limit ourselves to half the total */
2809 afs_maxvcount = nvnode / 2; /* limit ourselves to half the total */
2811 if (astatSize < afs_maxvcount) {
2812 afs_maxvcount = astatSize;
2815 #else /* AFS_OSF_ENV */
2819 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2820 LOCK_INIT(&afs_xvcb, "afs_xvcb");
2822 #if !defined(AFS_OSF_ENV)
2823 /* Allocate and thread the struct vcache entries */
2824 tvp = (struct vcache *)afs_osi_Alloc(astatSize * sizeof(struct vcache));
2825 memset((char *)tvp, 0, sizeof(struct vcache) * astatSize);
2827 Initial_freeVCList = tvp;
2828 freeVCList = &(tvp[0]);
2829 for (i = 0; i < astatSize - 1; i++) {
2830 tvp[i].nextfree = &(tvp[i + 1]);
2832 tvp[astatSize - 1].nextfree = NULL;
2833 #ifdef KERNEL_HAVE_PIN
2834 pin((char *)tvp, astatSize * sizeof(struct vcache)); /* XXX */
2839 #if defined(AFS_SGI_ENV)
2840 for (i = 0; i < astatSize; i++) {
2841 char name[METER_NAMSZ];
2842 struct vcache *tvc = &tvp[i];
2844 tvc->v.v_number = ++afsvnumbers;
2845 tvc->vc_rwlockid = OSI_NO_LOCKID;
2846 initnsema(&tvc->vc_rwlock, 1,
2847 makesname(name, "vrw", tvc->v.v_number));
2848 #ifndef AFS_SGI53_ENV
2849 initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
2851 #ifndef AFS_SGI62_ENV
2852 initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
2853 #endif /* AFS_SGI62_ENV */
2867 shutdown_vcache(void)
2870 struct afs_cbr *tsp, *nsp;
2872 * XXX We may potentially miss some of the vcaches because if when there're no
2873 * free vcache entries and all the vcache entries are active ones then we allocate
2874 * an additional one - admittedly we almost never had that occur.
2876 #if !defined(AFS_OSF_ENV)
2877 afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2879 #ifdef KERNEL_HAVE_PIN
2880 unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2884 register struct afs_q *tq, *uq;
2885 register struct vcache *tvc;
2886 for (tq = VLRU.prev; tq != &VLRU; tq = uq) {
2890 osi_FreeSmallSpace(tvc->mvid);
2891 tvc->mvid = (struct VenusFid *)0;
2894 aix_gnode_rele(AFSTOV(tvc));
2896 if (tvc->linkData) {
2897 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2902 * Also free the remaining ones in the Cache
2904 for (i = 0; i < VCSIZE; i++) {
2905 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2907 osi_FreeSmallSpace(tvc->mvid);
2908 tvc->mvid = (struct VenusFid *)0;
2912 afs_osi_Free(tvc->v.v_gnode, sizeof(struct gnode));
2913 #ifdef AFS_AIX32_ENV
2916 vms_delete(tvc->segid);
2918 tvc->segid = tvc->vmh = NULL;
2920 osi_Panic("flushVcache: vm race");
2928 #if defined(AFS_SUN5_ENV)
2934 if (tvc->linkData) {
2935 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2939 afs_FreeAllAxs(&(tvc->Access));
2945 * Free any leftover callback queue
2947 for (tsp = afs_cbrSpace; tsp; tsp = nsp) {
2949 afs_osi_Free((char *)tsp, AFS_NCBRS * sizeof(struct afs_cbr));
2953 #if !defined(AFS_OSF_ENV)
2954 freeVCList = Initial_freeVCList = 0;
2956 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2957 LOCK_INIT(&afs_xvcb, "afs_xvcb");