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 static struct afs_cbr *afs_cbrHashT[CBRSIZE];
73 afs_int32 afs_bulkStatsLost;
74 int afs_norefpanic = 0;
76 /* Forward declarations */
77 static afs_int32 afs_QueueVCB(struct vcache *avc);
82 * Generate an index into the hash table for a given Fid.
85 afs_HashCBRFid(struct AFSFid *fid) {
86 return (fid->Volume + fid->Vnode + fid->Unique) % CBRSIZE;
92 * Insert a CBR entry into the hash table.
93 * Must be called with afs_xvcb held.
96 afs_InsertHashCBR(struct afs_cbr *cbr) {
97 int slot = afs_HashCBRFid(&cbr->fid);
99 cbr->hash_next = afs_cbrHashT[slot];
100 if (afs_cbrHashT[slot])
101 afs_cbrHashT[slot]->hash_pprev = &cbr->hash_next;
103 cbr->hash_pprev = &afs_cbrHashT[slot];
104 afs_cbrHashT[slot] = cbr;
111 * Flush the given vcache entry.
114 * avc : Pointer to vcache entry to flush.
115 * slept : Pointer to int to set 1 if we sleep/drop locks, 0 if we don't.
118 * afs_xvcache lock must be held for writing upon entry to
119 * prevent people from changing the vrefCount field, and to
120 * protect the lruq and hnext fields.
121 * LOCK: afs_FlushVCache afs_xvcache W
122 * REFCNT: vcache ref count must be zero on entry except for osf1
123 * RACE: lock is dropped and reobtained, permitting race in caller
127 afs_FlushVCache(struct vcache *avc, int *slept)
128 { /*afs_FlushVCache */
130 register afs_int32 i, code;
131 register struct vcache **uvc, *wvc;
134 AFS_STATCNT(afs_FlushVCache);
135 afs_Trace2(afs_iclSetp, CM_TRACE_FLUSHV, ICL_TYPE_POINTER, avc,
136 ICL_TYPE_INT32, avc->states);
139 VN_LOCK(AFSTOV(avc));
143 code = osi_VM_FlushVCache(avc, slept);
147 if (avc->states & CVFlushed) {
151 if (avc->nextfree || !avc->vlruq.prev || !avc->vlruq.next) { /* qv afs.h */
152 refpanic("LRU vs. Free inconsistency");
154 avc->states |= CVFlushed;
155 /* pull the entry out of the lruq and put it on the free list */
156 QRemove(&avc->vlruq);
157 avc->vlruq.prev = avc->vlruq.next = (struct afs_q *)0;
159 /* keep track of # of files that we bulk stat'd, but never used
160 * before they got recycled.
162 if (avc->states & CBulkStat)
165 /* remove entry from the hash chain */
166 i = VCHash(&avc->fid);
167 uvc = &afs_vhashT[i];
168 for (wvc = *uvc; wvc; uvc = &wvc->hnext, wvc = *uvc) {
171 avc->hnext = (struct vcache *)NULL;
176 osi_Panic("flushvcache"); /* not in correct hash bucket */
178 osi_FreeSmallSpace(avc->mvid);
179 avc->mvid = (struct VenusFid *)0;
181 afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
182 avc->linkData = NULL;
184 #if defined(AFS_XBSD_ENV)
185 /* OK, there are no internal vrefCounts, so there shouldn't
186 * be any more refs here. */
188 avc->v->v_data = NULL; /* remove from vnode */
189 avc->v = NULL; /* also drop the ptr to vnode */
192 afs_FreeAllAxs(&(avc->Access));
194 /* we can't really give back callbacks on RO files, since the
195 * server only tracks them on a per-volume basis, and we don't
196 * know whether we still have some other files from the same
198 if ((avc->states & CRO) == 0 && avc->callback) {
201 ObtainWriteLock(&afs_xcbhash, 460);
202 afs_DequeueCallback(avc); /* remove it from queued callbacks list */
203 avc->states &= ~(CStatd | CUnique);
204 ReleaseWriteLock(&afs_xcbhash);
205 afs_symhint_inval(avc);
206 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
207 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
209 osi_dnlc_purgevp(avc);
212 * Next, keep track of which vnodes we've deleted for create's
213 * optimistic synchronization algorithm
216 if (avc->fid.Fid.Vnode & 1)
221 #if !defined(AFS_OSF_ENV)
222 /* put the entry in the free list */
223 avc->nextfree = freeVCList;
225 if (avc->vlruq.prev || avc->vlruq.next) {
226 refpanic("LRU vs. Free inconsistency");
229 /* This should put it back on the vnode free list since usecount is 1 */
232 if (VREFCOUNT(avc) > 0) {
233 VN_UNLOCK(AFSTOV(avc));
234 AFS_RELE(AFSTOV(avc));
236 if (afs_norefpanic) {
237 printf("flush vc refcnt < 1");
239 (void)vgone(avc, VX_NOSLEEP, NULL);
241 VN_UNLOCK(AFSTOV(avc));
243 osi_Panic("flush vc refcnt < 1");
245 #endif /* AFS_OSF_ENV */
246 avc->states |= CVFlushed;
251 VN_UNLOCK(AFSTOV(avc));
255 } /*afs_FlushVCache */
261 * The core of the inactive vnode op for all but IRIX.
264 afs_InactiveVCache(struct vcache *avc, struct AFS_UCRED *acred)
266 AFS_STATCNT(afs_inactive);
267 if (avc->states & CDirty) {
268 /* we can't keep trying to push back dirty data forever. Give up. */
269 afs_InvalidateAllSegments(avc); /* turns off dirty bit */
271 avc->states &= ~CMAPPED; /* mainly used by SunOS 4.0.x */
272 avc->states &= ~CDirty; /* Turn it off */
273 if (avc->states & CUnlinked) {
274 if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache)) {
275 avc->states |= CUnlinkedDel;
278 afs_remunlink(avc, 1); /* ignore any return code */
287 * Description: allocate a callback return structure from the
288 * free list and return it.
290 * Env: The alloc and free routines are both called with the afs_xvcb lock
291 * held, so we don't have to worry about blocking in osi_Alloc.
293 static struct afs_cbr *afs_cbrSpace = 0;
297 register struct afs_cbr *tsp;
300 while (!afs_cbrSpace) {
301 if (afs_stats_cmperf.CallBackAlloced >= 2) {
302 /* don't allocate more than 2 * AFS_NCBRS for now */
304 afs_stats_cmperf.CallBackFlushes++;
308 (struct afs_cbr *)afs_osi_Alloc(AFS_NCBRS *
309 sizeof(struct afs_cbr));
310 for (i = 0; i < AFS_NCBRS - 1; i++) {
311 tsp[i].next = &tsp[i + 1];
313 tsp[AFS_NCBRS - 1].next = 0;
315 afs_stats_cmperf.CallBackAlloced++;
319 afs_cbrSpace = tsp->next;
326 * Description: free a callback return structure, removing it from all lists.
329 * asp -- the address of the structure to free.
331 * Environment: the xvcb lock is held over these calls.
334 afs_FreeCBR(register struct afs_cbr *asp)
336 *(asp->pprev) = asp->next;
338 asp->next->pprev = asp->pprev;
340 *(asp->hash_pprev) = asp->hash_next;
342 asp->hash_next->hash_pprev = asp->hash_pprev;
344 asp->next = afs_cbrSpace;
352 * Description: flush all queued callbacks to all servers.
356 * Environment: holds xvcb lock over RPC to guard against race conditions
357 * when a new callback is granted for the same file later on.
360 afs_FlushVCBs(afs_int32 lockit)
362 struct AFSFid *tfids;
363 struct AFSCallBack callBacks[1];
364 struct AFSCBFids fidArray;
365 struct AFSCBs cbArray;
367 struct afs_cbr *tcbrp;
371 struct vrequest treq;
373 int safety1, safety2, safety3;
374 XSTATS_DECLS if ((code = afs_InitReq(&treq, afs_osi_credp)))
376 treq.flags |= O_NONBLOCK;
377 tfids = afs_osi_Alloc(sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
380 MObtainWriteLock(&afs_xvcb, 273);
381 ObtainReadLock(&afs_xserver);
382 for (i = 0; i < NSERVERS; i++) {
383 for (safety1 = 0, tsp = afs_servers[i];
384 tsp && safety1 < afs_totalServers + 10;
385 tsp = tsp->next, safety1++) {
387 if (tsp->cbrs == (struct afs_cbr *)0)
390 /* otherwise, grab a block of AFS_MAXCBRSCALL from the list
391 * and make an RPC, over and over again.
393 tcount = 0; /* number found so far */
394 for (safety2 = 0; safety2 < afs_cacheStats; safety2++) {
395 if (tcount >= AFS_MAXCBRSCALL || !tsp->cbrs) {
396 /* if buffer is full, or we've queued all we're going
397 * to from this server, we should flush out the
400 fidArray.AFSCBFids_len = tcount;
401 fidArray.AFSCBFids_val = (struct AFSFid *)tfids;
402 cbArray.AFSCBs_len = 1;
403 cbArray.AFSCBs_val = callBacks;
404 memset(&callBacks[0], 0, sizeof(callBacks[0]));
405 callBacks[0].CallBackType = CB_EXCLUSIVE;
406 for (safety3 = 0; safety3 < MAXHOSTS * 2; safety3++) {
407 tc = afs_ConnByHost(tsp, tsp->cell->fsport,
408 tsp->cell->cellNum, &treq, 0,
412 (AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
415 RXAFS_GiveUpCallBacks(tc->id, &fidArray,
423 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK,
428 /* ignore return code, since callbacks may have
429 * been returned anyway, we shouldn't leave them
430 * around to be returned again.
432 * Next, see if we are done with this server, and if so,
433 * break to deal with the next one.
439 /* if to flush full buffer */
440 /* if we make it here, we have an entry at the head of cbrs,
441 * which we should copy to the file ID array and then free.
444 tfids[tcount++] = tcbrp->fid;
446 /* Freeing the CBR will unlink it from the server's CBR list */
448 } /* while loop for this one server */
449 if (safety2 > afs_cacheStats) {
450 afs_warn("possible internal error afs_flushVCBs (%d)\n",
453 } /* for loop for this hash chain */
454 } /* loop through all hash chains */
455 if (safety1 > afs_totalServers + 2) {
457 ("AFS internal error (afs_flushVCBs) (%d > %d), continuing...\n",
458 safety1, afs_totalServers + 2);
460 osi_Panic("afs_flushVCBS safety1");
463 ReleaseReadLock(&afs_xserver);
465 MReleaseWriteLock(&afs_xvcb);
466 afs_osi_Free(tfids, sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
474 * Queue a callback on the given fid.
480 * Locks the xvcb lock.
481 * Called when the xvcache lock is already held.
485 afs_QueueVCB(struct vcache *avc)
488 struct afs_cbr *tcbp;
490 AFS_STATCNT(afs_QueueVCB);
491 /* The callback is really just a struct server ptr. */
492 tsp = (struct server *)(avc->callback);
494 /* we now have a pointer to the server, so we just allocate
495 * a queue entry and queue it.
497 MObtainWriteLock(&afs_xvcb, 274);
498 tcbp = afs_AllocCBR();
499 tcbp->fid = avc->fid.Fid;
501 tcbp->next = tsp->cbrs;
503 tsp->cbrs->pprev = &tcbp->next;
506 tcbp->pprev = &tsp->cbrs;
508 afs_InsertHashCBR(tcbp);
510 /* now release locks and return */
511 MReleaseWriteLock(&afs_xvcb);
520 * Remove a queued callback for a given Fid.
523 * afid: The fid we want cleansed of queued callbacks.
526 * Locks xvcb and xserver locks.
527 * Typically called with xdcache, xvcache and/or individual vcache
532 afs_RemoveVCB(struct VenusFid *afid)
535 struct afs_cbr *cbr, *ncbr;
537 AFS_STATCNT(afs_RemoveVCB);
538 MObtainWriteLock(&afs_xvcb, 275);
540 slot = afs_HashCBRFid(&afid->Fid);
541 ncbr = afs_cbrHashT[slot];
545 ncbr = cbr->hash_next;
547 if (afid->Fid.Volume == cbr->fid.Volume &&
548 afid->Fid.Vnode == cbr->fid.Vnode &&
549 afid->Fid.Unique == cbr->fid.Unique) {
554 MReleaseWriteLock(&afs_xvcb);
557 #if defined(AFS_LINUX22_ENV) && !defined(AFS_LINUX26_ENV)
560 __shrink_dcache_parent(struct dentry *parent)
562 struct dentry *this_parent = parent;
563 struct list_head *next;
565 LIST_HEAD(afs_dentry_unused);
568 next = this_parent->d_subdirs.next;
570 while (next != &this_parent->d_subdirs) {
571 struct list_head *tmp = next;
572 struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
574 if (!DCOUNT(dentry)) {
575 list_del(&dentry->d_lru);
576 list_add(&dentry->d_lru, afs_dentry_unused.prev);
580 * Descend a level if the d_subdirs list is non-empty.
582 if (!list_empty(&dentry->d_subdirs)) {
583 this_parent = dentry;
588 * All done at this level ... ascend and resume the search.
590 if (this_parent != parent) {
591 next = this_parent->d_child.next;
592 this_parent = this_parent->d_parent;
597 struct dentry *dentry;
598 struct list_head *tmp;
600 tmp = afs_dentry_unused.prev;
602 if (tmp == &afs_dentry_unused)
604 #ifdef AFS_LINUX24_ENV
609 #endif /* AFS_LINUX24_ENV */
610 dentry = list_entry(tmp, struct dentry, d_lru);
612 #ifdef AFS_LINUX24_ENV
613 /* Unused dentry with a count? */
618 #ifdef AFS_LINUX24_ENV
619 list_del_init(&dentry->d_hash); /* d_drop */
621 list_del(&dentry->d_hash);
622 INIT_LIST_HEAD(&dentry->d_hash);
623 #endif /* AFS_LINUX24_ENV */
632 /* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
633 * children of the dentry
635 * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
636 * AFS_GLOCK, so it can call dput, which may call iput, but
637 * keeps afs_xvcache exclusively.
639 * Tree traversal algorithm from fs/dcache.c: select_parent()
642 afs_TryFlushDcacheChildren(struct vcache *tvc)
644 struct inode *ip = AFSTOI(tvc);
645 struct dentry *this_parent;
646 struct list_head *next;
647 struct list_head *cur;
648 struct list_head *head = &ip->i_dentry;
649 struct dentry *dentry;
653 #ifndef old_vcache_scheme
656 while ((cur = cur->next) != head) {
657 dentry = list_entry(cur, struct dentry, d_alias);
659 afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN,
660 ICL_TYPE_POINTER, ip, ICL_TYPE_STRING,
661 dentry->d_parent->d_name.name, ICL_TYPE_STRING,
662 dentry->d_name.name);
664 if (!list_empty(&dentry->d_hash) && !list_empty(&dentry->d_subdirs))
665 __shrink_dcache_parent(dentry);
667 if (!DCOUNT(dentry)) {
669 #ifdef AFS_LINUX24_ENV
670 list_del_init(&dentry->d_hash); /* d_drop */
672 list_del(&dentry->d_hash);
673 INIT_LIST_HEAD(&dentry->d_hash);
674 #endif /* AFS_LINUX24_ENV */
686 while ((cur = cur->next) != head) {
687 dentry = list_entry(cur, struct dentry, d_alias);
689 afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN,
690 ICL_TYPE_POINTER, ip, ICL_TYPE_STRING,
691 dentry->d_parent->d_name.name, ICL_TYPE_STRING,
692 dentry->d_name.name);
694 if (!DCOUNT(dentry)) {
707 #endif /* AFS_LINUX22_ENV && !AFS_LINUX26_ENV */
713 * This routine is responsible for allocating a new cache entry
714 * from the free list. It formats the cache entry and inserts it
715 * into the appropriate hash tables. It must be called with
716 * afs_xvcache write-locked so as to prevent several processes from
717 * trying to create a new cache entry simultaneously.
720 * afid : The file id of the file whose cache entry is being
723 /* LOCK: afs_NewVCache afs_xvcache W */
725 afs_NewVCache(struct VenusFid *afid, struct server *serverp)
729 afs_int32 anumber = VCACHE_FREE;
731 struct gnode *gnodepnt;
734 struct vm_info *vm_info_ptr;
735 #endif /* AFS_MACH_ENV */
738 #endif /* AFS_OSF_ENV */
739 struct afs_q *tq, *uq;
742 AFS_STATCNT(afs_NewVCache);
745 if (afs_vcount >= afs_maxvcount) {
748 * If we are using > 33 % of the total system vnodes for AFS vcache
749 * entries or we are using the maximum number of vcache entries,
750 * then free some. (if our usage is > 33% we should free some, if
751 * our usage is > afs_maxvcount, set elsewhere to 0.5*nvnode,
752 * we _must_ free some -- no choice).
754 if (((3 * afs_vcount) > nvnode) || (afs_vcount >= afs_maxvcount)) {
756 struct afs_q *tq, *uq;
761 for (tq = VLRU.prev; tq != &VLRU && anumber > 0; tq = uq) {
764 if (tvc->states & CVFlushed)
765 refpanic("CVFlushed on VLRU");
766 else if (i++ > afs_maxvcount)
767 refpanic("Exceeded pool of AFS vnodes(VLRU cycle?)");
768 else if (QNext(uq) != tq)
769 refpanic("VLRU inconsistent");
770 else if (VREFCOUNT(tvc) < 1)
771 refpanic("refcnt 0 on VLRU");
773 if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
774 && (tvc->states & CUnlinkedDel) == 0) {
775 code = afs_FlushVCache(tvc, &fv_slept);
782 continue; /* start over - may have raced. */
788 if (anumber == VCACHE_FREE) {
789 printf("NewVCache: warning none freed, using %d of %d\n",
790 afs_vcount, afs_maxvcount);
791 if (afs_vcount >= afs_maxvcount) {
792 osi_Panic("NewVCache - none freed");
793 /* XXX instead of panicing, should do afs_maxvcount++
794 * and magic up another one */
800 if (getnewvnode(MOUNT_AFS, &Afs_vnodeops, &nvc)) {
801 /* What should we do ???? */
802 osi_Panic("afs_NewVCache: no more vnodes");
807 tvc->nextfree = NULL;
809 #else /* AFS_OSF_ENV */
810 /* pull out a free cache entry */
813 for (tq = VLRU.prev; (anumber > 0) && (tq != &VLRU); tq = uq) {
817 if (tvc->states & CVFlushed) {
818 refpanic("CVFlushed on VLRU");
819 } else if (i++ > 2 * afs_cacheStats) { /* even allowing for a few xallocs... */
820 refpanic("Increase -stat parameter of afsd(VLRU cycle?)");
821 } else if (QNext(uq) != tq) {
822 refpanic("VLRU inconsistent");
824 #ifdef AFS_DARWIN_ENV
825 if (tvc->opens == 0 && ((tvc->states & CUnlinkedDel) == 0)
826 && VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
827 osi_VM_TryReclaim(tvc, &fv_slept);
831 continue; /* start over - may have raced. */
834 #elif defined(AFS_LINUX22_ENV)
835 if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0) {
836 #if defined(AFS_LINUX26_ENV)
838 d_prune_aliases(AFSTOI(tvc));
841 afs_TryFlushDcacheChildren(tvc);
846 if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
847 && (tvc->states & CUnlinkedDel) == 0) {
848 #if defined(AFS_XBSD_ENV)
850 * vgone() reclaims the vnode, which calls afs_FlushVCache(),
851 * then it puts the vnode on the free list.
852 * If we don't do this we end up with a cleaned vnode that's
853 * not on the free list.
854 * XXX assume FreeBSD is the same for now.
859 code = afs_FlushVCache(tvc, &fv_slept);
867 continue; /* start over - may have raced. */
875 /* none free, making one is better than a panic */
876 afs_stats_cmperf.vcacheXAllocs++; /* count in case we have a leak */
877 tvc = (struct vcache *)afs_osi_Alloc(sizeof(struct vcache));
878 #ifdef KERNEL_HAVE_PIN
879 pin((char *)tvc, sizeof(struct vcache)); /* XXX */
882 /* In case it still comes here we need to fill this */
883 tvc->v.v_vm_info = VM_INFO_NULL;
884 vm_info_init(tvc->v.v_vm_info);
885 /* perhaps we should also do close_flush on non-NeXT mach systems;
886 * who knows; we don't currently have the sources.
888 #endif /* AFS_MACH_ENV */
889 #if defined(AFS_SGI_ENV)
891 char name[METER_NAMSZ];
892 memset(tvc, 0, sizeof(struct vcache));
893 tvc->v.v_number = ++afsvnumbers;
894 tvc->vc_rwlockid = OSI_NO_LOCKID;
895 initnsema(&tvc->vc_rwlock, 1,
896 makesname(name, "vrw", tvc->v.v_number));
897 #ifndef AFS_SGI53_ENV
898 initnsema(&tvc->v.v_sync, 0,
899 makesname(name, "vsy", tvc->v.v_number));
901 #ifndef AFS_SGI62_ENV
902 initnlock(&tvc->v.v_lock,
903 makesname(name, "vlk", tvc->v.v_number));
906 #endif /* AFS_SGI_ENV */
908 tvc = freeVCList; /* take from free list */
909 freeVCList = tvc->nextfree;
910 tvc->nextfree = NULL;
912 #endif /* AFS_OSF_ENV */
915 vm_info_ptr = tvc->v.v_vm_info;
916 #endif /* AFS_MACH_ENV */
918 #if defined(AFS_XBSD_ENV)
920 panic("afs_NewVCache(): free vcache with vnode attached");
923 #if !defined(AFS_SGI_ENV) && !defined(AFS_OSF_ENV)
924 memset((char *)tvc, 0, sizeof(struct vcache));
929 RWLOCK_INIT(&tvc->lock, "vcache lock");
930 #if defined(AFS_SUN5_ENV)
931 RWLOCK_INIT(&tvc->vlock, "vcache vlock");
932 #endif /* defined(AFS_SUN5_ENV) */
935 tvc->v.v_vm_info = vm_info_ptr;
936 tvc->v.v_vm_info->pager = MEMORY_OBJECT_NULL;
937 #endif /* AFS_MACH_ENV */
940 afs_nbsd_getnewvnode(tvc); /* includes one refcount */
942 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
949 #ifdef AFS_FBSD50_ENV
950 if (getnewvnode(MOUNT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
952 if (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
954 panic("afs getnewvnode"); /* can't happen */
956 if (tvc->v != NULL) {
957 /* I'd like to know if this ever happens...
958 We don't drop global for the rest of this function,
959 so if we do lose the race, the other thread should
960 have found the same vnode and finished initializing
961 the vcache entry. Is it conceivable that this vcache
962 entry could be recycled during this interval? If so,
963 then there probably needs to be some sort of additional
964 mutual exclusion (an Embryonic flag would suffice).
966 printf("afs_NewVCache: lost the race\n");
970 tvc->v->v_data = tvc;
971 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
974 tvc->parentVnode = 0;
976 tvc->linkData = NULL;
979 tvc->execsOrWriters = 0;
983 tvc->last_looker = 0;
985 tvc->asynchrony = -1;
987 afs_symhint_inval(tvc);
989 tvc->flushDV.low = tvc->flushDV.high = AFS_MAXDV;
992 tvc->truncPos = AFS_NOTRUNC; /* don't truncate until we need to */
993 hzero(tvc->m.DataVersion); /* in case we copy it into flushDV */
994 #if defined(AFS_LINUX22_ENV)
996 struct inode *ip = AFSTOI(tvc);
997 struct address_space *mapping = &ip->i_data;
999 #if defined(AFS_LINUX26_ENV)
1000 inode_init_once(ip);
1002 sema_init(&ip->i_sem, 1);
1003 INIT_LIST_HEAD(&ip->i_hash);
1004 INIT_LIST_HEAD(&ip->i_dentry);
1005 #if defined(AFS_LINUX24_ENV)
1006 sema_init(&ip->i_zombie, 1);
1007 init_waitqueue_head(&ip->i_wait);
1008 spin_lock_init(&ip->i_data.i_shared_lock);
1009 #ifdef STRUCT_ADDRESS_SPACE_HAS_PAGE_LOCK
1010 spin_lock_init(&ip->i_data.page_lock);
1012 INIT_LIST_HEAD(&ip->i_data.clean_pages);
1013 INIT_LIST_HEAD(&ip->i_data.dirty_pages);
1014 INIT_LIST_HEAD(&ip->i_data.locked_pages);
1015 INIT_LIST_HEAD(&ip->i_dirty_buffers);
1016 #ifdef STRUCT_INODE_HAS_I_DIRTY_DATA_BUFFERS
1017 INIT_LIST_HEAD(&ip->i_dirty_data_buffers);
1019 #ifdef STRUCT_INODE_HAS_I_DEVICES
1020 INIT_LIST_HEAD(&ip->i_devices);
1022 #ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
1023 init_rwsem(&ip->i_truncate_sem);
1025 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
1026 init_rwsem(&ip->i_alloc_sem);
1029 #else /* AFS_LINUX22_ENV */
1030 sema_init(&ip->i_atomic_write, 1);
1031 init_waitqueue(&ip->i_wait);
1035 #if defined(AFS_LINUX24_ENV)
1037 ip->i_mapping = mapping;
1038 #ifdef STRUCT_ADDRESS_SPACE_HAS_GFP_MASK
1039 ip->i_data.gfp_mask = GFP_HIGHUSER;
1041 #if defined(AFS_LINUX26_ENV)
1042 mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
1044 extern struct backing_dev_info afs_backing_dev_info;
1046 mapping->backing_dev_info = &afs_backing_dev_info;
1051 #if !defined(AFS_LINUX26_ENV)
1053 ip->i_dev = afs_globalVFS->s_dev;
1055 ip->i_sb = afs_globalVFS;
1056 put_inode_on_dummy_list(ip);
1061 /* Hold it for the LRU (should make count 2) */
1062 VN_HOLD(AFSTOV(tvc));
1063 #else /* AFS_OSF_ENV */
1064 #if !defined(AFS_XBSD_ENV)
1065 VREFCOUNT_SET(tvc, 1); /* us */
1066 #endif /* AFS_XBSD_ENV */
1067 #endif /* AFS_OSF_ENV */
1068 #ifdef AFS_AIX32_ENV
1069 LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
1070 tvc->vmh = tvc->segid = NULL;
1073 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1074 #if defined(AFS_SUN5_ENV)
1075 rw_init(&tvc->rwlock, "vcache rwlock", RW_DEFAULT, NULL);
1077 #if defined(AFS_SUN55_ENV)
1078 /* This is required if the kaio (kernel aynchronous io)
1079 ** module is installed. Inside the kernel, the function
1080 ** check_vp( common/os/aio.c) checks to see if the kernel has
1081 ** to provide asynchronous io for this vnode. This
1082 ** function extracts the device number by following the
1083 ** v_data field of the vnode. If we do not set this field
1084 ** then the system panics. The value of the v_data field
1085 ** is not really important for AFS vnodes because the kernel
1086 ** does not do asynchronous io for regular files. Hence,
1087 ** for the time being, we fill up the v_data field with the
1088 ** vnode pointer itself. */
1089 tvc->v.v_data = (char *)tvc;
1090 #endif /* AFS_SUN55_ENV */
1092 afs_BozonInit(&tvc->pvnLock, tvc);
1096 tvc->callback = serverp; /* to minimize chance that clear
1097 * request is lost */
1098 /* initialize vnode data, note vrefCount is v.v_count */
1100 /* Don't forget to free the gnode space */
1101 tvc->v.v_gnode = gnodepnt =
1102 (struct gnode *)osi_AllocSmallSpace(sizeof(struct gnode));
1103 memset((char *)gnodepnt, 0, sizeof(struct gnode));
1105 #ifdef AFS_SGI64_ENV
1106 memset((void *)&(tvc->vc_bhv_desc), 0, sizeof(tvc->vc_bhv_desc));
1107 bhv_desc_init(&(tvc->vc_bhv_desc), tvc, tvc, &Afs_vnodeops);
1108 #ifdef AFS_SGI65_ENV
1109 vn_bhv_head_init(&(tvc->v.v_bh), "afsvp");
1110 vn_bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1112 bhv_head_init(&(tvc->v.v_bh));
1113 bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1115 #ifdef AFS_SGI65_ENV
1116 tvc->v.v_mreg = tvc->v.v_mregb = (struct pregion *)tvc;
1117 #ifdef VNODE_TRACING
1118 tvc->v.v_trace = ktrace_alloc(VNODE_TRACE_SIZE, 0);
1120 init_bitlock(&tvc->v.v_pcacheflag, VNODE_PCACHE_LOCKBIT, "afs_pcache",
1122 init_mutex(&tvc->v.v_filocksem, MUTEX_DEFAULT, "afsvfl", (long)tvc);
1123 init_mutex(&tvc->v.v_buf_lock, MUTEX_DEFAULT, "afsvnbuf", (long)tvc);
1125 vnode_pcache_init(&tvc->v);
1126 #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
1127 /* Above define is never true execpt in SGI test kernels. */
1128 init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number);
1130 #ifdef INTR_KTHREADS
1131 AFS_VN_INIT_BUF_LOCK(&(tvc->v));
1134 SetAfsVnode(AFSTOV(tvc));
1135 #endif /* AFS_SGI64_ENV */
1136 #ifdef AFS_DARWIN_ENV
1137 tvc->v.v_ubcinfo = UBC_INFO_NULL;
1138 lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
1139 cache_purge(AFSTOV(tvc));
1140 tvc->v.v_data = tvc;
1141 tvc->v.v_tag = VT_AFS;
1142 /* VLISTNONE(&tvc->v); */
1143 tvc->v.v_freelist.tqe_next = 0;
1144 tvc->v.v_freelist.tqe_prev = (struct vnode **)0xdeadb;
1145 /*tvc->vrefCount++; */
1148 * The proper value for mvstat (for root fids) is setup by the caller.
1151 if (afid->Fid.Vnode == 1 && afid->Fid.Unique == 1)
1153 if (afs_globalVFS == 0)
1154 osi_Panic("afs globalvfs");
1155 vSetVfsp(tvc, afs_globalVFS);
1156 vSetType(tvc, VREG);
1158 tvc->v.v_vfsnext = afs_globalVFS->vfs_vnodes; /* link off vfs */
1159 tvc->v.v_vfsprev = NULL;
1160 afs_globalVFS->vfs_vnodes = &tvc->v;
1161 if (tvc->v.v_vfsnext != NULL)
1162 tvc->v.v_vfsnext->v_vfsprev = &tvc->v;
1163 tvc->v.v_next = gnodepnt->gn_vnode; /*Single vnode per gnode for us! */
1164 gnodepnt->gn_vnode = &tvc->v;
1167 tvc->v.g_dev = ((struct mount *)afs_globalVFS->vfs_data)->m_dev;
1169 #if defined(AFS_DUX40_ENV)
1170 insmntque(tvc, afs_globalVFS, &afs_ubcops);
1173 /* Is this needed??? */
1174 insmntque(tvc, afs_globalVFS);
1175 #endif /* AFS_OSF_ENV */
1176 #endif /* AFS_DUX40_ENV */
1177 #if defined(AFS_SGI_ENV)
1178 VN_SET_DPAGES(&(tvc->v), (struct pfdat *)NULL);
1179 osi_Assert((tvc->v.v_flag & VINACT) == 0);
1181 osi_Assert(VN_GET_PGCNT(&(tvc->v)) == 0);
1182 osi_Assert(tvc->mapcnt == 0 && tvc->vc_locktrips == 0);
1183 osi_Assert(tvc->vc_rwlockid == OSI_NO_LOCKID);
1184 osi_Assert(tvc->v.v_filocks == NULL);
1185 #if !defined(AFS_SGI65_ENV)
1186 osi_Assert(tvc->v.v_filocksem == NULL);
1188 osi_Assert(tvc->cred == NULL);
1189 #ifdef AFS_SGI64_ENV
1190 vnode_pcache_reinit(&tvc->v);
1191 tvc->v.v_rdev = NODEV;
1193 vn_initlist((struct vnlist *)&tvc->v);
1195 #endif /* AFS_SGI_ENV */
1197 osi_dnlc_purgedp(tvc); /* this may be overkill */
1198 memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
1199 memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
1203 tvc->hnext = afs_vhashT[i];
1204 afs_vhashT[i] = tvc;
1205 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1206 refpanic("NewVCache VLRU inconsistent");
1208 QAdd(&VLRU, &tvc->vlruq); /* put in lruq */
1209 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1210 refpanic("NewVCache VLRU inconsistent2");
1212 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
1213 refpanic("NewVCache VLRU inconsistent3");
1215 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
1216 refpanic("NewVCache VLRU inconsistent4");
1222 } /*afs_NewVCache */
1226 * afs_FlushActiveVcaches
1232 * doflocks : Do we handle flocks?
1234 /* LOCK: afs_FlushActiveVcaches afs_xvcache N */
1236 afs_FlushActiveVcaches(register afs_int32 doflocks)
1238 register struct vcache *tvc;
1240 register struct conn *tc;
1241 register afs_int32 code;
1242 register struct AFS_UCRED *cred = NULL;
1243 struct vrequest treq, ureq;
1244 struct AFSVolSync tsync;
1246 XSTATS_DECLS AFS_STATCNT(afs_FlushActiveVcaches);
1247 ObtainReadLock(&afs_xvcache);
1248 for (i = 0; i < VCSIZE; i++) {
1249 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1250 if (doflocks && tvc->flockCount != 0) {
1251 /* if this entry has an flock, send a keep-alive call out */
1253 ReleaseReadLock(&afs_xvcache);
1254 ObtainWriteLock(&tvc->lock, 51);
1256 afs_InitReq(&treq, afs_osi_credp);
1257 treq.flags |= O_NONBLOCK;
1259 tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
1261 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
1264 RXAFS_ExtendLock(tc->id,
1265 (struct AFSFid *)&tvc->fid.Fid,
1271 } while (afs_Analyze
1272 (tc, code, &tvc->fid, &treq,
1273 AFS_STATS_FS_RPCIDX_EXTENDLOCK, SHARED_LOCK, NULL));
1275 ReleaseWriteLock(&tvc->lock);
1276 ObtainReadLock(&afs_xvcache);
1280 if ((tvc->states & CCore) || (tvc->states & CUnlinkedDel)) {
1282 * Don't let it evaporate in case someone else is in
1283 * this code. Also, drop the afs_xvcache lock while
1284 * getting vcache locks.
1287 ReleaseReadLock(&afs_xvcache);
1288 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1289 afs_BozonLock(&tvc->pvnLock, tvc);
1291 #if defined(AFS_SGI_ENV)
1293 * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
1295 osi_Assert(VREFCOUNT(tvc) > 0);
1296 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1298 ObtainWriteLock(&tvc->lock, 52);
1299 if (tvc->states & CCore) {
1300 tvc->states &= ~CCore;
1301 /* XXXX Find better place-holder for cred XXXX */
1302 cred = (struct AFS_UCRED *)tvc->linkData;
1303 tvc->linkData = NULL; /* XXX */
1304 afs_InitReq(&ureq, cred);
1305 afs_Trace2(afs_iclSetp, CM_TRACE_ACTCCORE,
1306 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32,
1307 tvc->execsOrWriters);
1308 code = afs_StoreOnLastReference(tvc, &ureq);
1309 ReleaseWriteLock(&tvc->lock);
1310 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1311 afs_BozonUnlock(&tvc->pvnLock, tvc);
1313 hzero(tvc->flushDV);
1316 if (code && code != VNOVNODE) {
1317 afs_StoreWarn(code, tvc->fid.Fid.Volume,
1318 /* /dev/console */ 1);
1320 } else if (tvc->states & CUnlinkedDel) {
1324 ReleaseWriteLock(&tvc->lock);
1325 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1326 afs_BozonUnlock(&tvc->pvnLock, tvc);
1328 #if defined(AFS_SGI_ENV)
1329 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1331 afs_remunlink(tvc, 0);
1332 #if defined(AFS_SGI_ENV)
1333 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1336 /* lost (or won, perhaps) the race condition */
1337 ReleaseWriteLock(&tvc->lock);
1338 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1339 afs_BozonUnlock(&tvc->pvnLock, tvc);
1342 #if defined(AFS_SGI_ENV)
1343 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1345 ObtainReadLock(&afs_xvcache);
1351 AFS_RELE(AFSTOV(tvc));
1353 /* Matches write code setting CCore flag */
1357 #ifdef AFS_DARWIN_ENV
1358 if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
1360 panic("flushactive open, hasubc, but refcnt 1");
1361 osi_VM_TryReclaim(tvc, 0);
1366 ReleaseReadLock(&afs_xvcache);
1374 * Make sure a cache entry is up-to-date status-wise.
1376 * NOTE: everywhere that calls this can potentially be sped up
1377 * by checking CStatd first, and avoiding doing the InitReq
1378 * if this is up-to-date.
1380 * Anymore, the only places that call this KNOW already that the
1381 * vcache is not up-to-date, so we don't screw around.
1384 * avc : Ptr to vcache entry to verify.
1389 afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq)
1391 register struct vcache *tvc;
1393 AFS_STATCNT(afs_VerifyVCache);
1395 #if defined(AFS_OSF_ENV)
1396 ObtainReadLock(&avc->lock);
1397 if (afs_IsWired(avc)) {
1398 ReleaseReadLock(&avc->lock);
1401 ReleaseReadLock(&avc->lock);
1402 #endif /* AFS_OSF_ENV */
1403 /* otherwise we must fetch the status info */
1405 ObtainWriteLock(&avc->lock, 53);
1406 if (avc->states & CStatd) {
1407 ReleaseWriteLock(&avc->lock);
1410 ObtainWriteLock(&afs_xcbhash, 461);
1411 avc->states &= ~(CStatd | CUnique);
1412 avc->callback = NULL;
1413 afs_DequeueCallback(avc);
1414 ReleaseWriteLock(&afs_xcbhash);
1415 ReleaseWriteLock(&avc->lock);
1417 /* since we've been called back, or the callback has expired,
1418 * it's possible that the contents of this directory, or this
1419 * file's name have changed, thus invalidating the dnlc contents.
1421 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1422 osi_dnlc_purgedp(avc);
1424 osi_dnlc_purgevp(avc);
1426 /* fetch the status info */
1427 tvc = afs_GetVCache(&avc->fid, areq, NULL, avc);
1430 /* Put it back; caller has already incremented vrefCount */
1434 } /*afs_VerifyVCache */
1441 * Simple copy of stat info into cache.
1444 * avc : Ptr to vcache entry involved.
1445 * astat : Ptr to stat info to copy.
1448 * Nothing interesting.
1450 * Callers: as of 1992-04-29, only called by WriteVCache
1453 afs_SimpleVStat(register struct vcache *avc,
1454 register struct AFSFetchStatus *astat, struct vrequest *areq)
1457 AFS_STATCNT(afs_SimpleVStat);
1460 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1461 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1463 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1465 #ifdef AFS_64BIT_CLIENT
1466 FillInt64(length, astat->Length_hi, astat->Length);
1467 #else /* AFS_64BIT_CLIENT */
1468 length = astat->Length;
1469 #endif /* AFS_64BIT_CLIENT */
1470 #if defined(AFS_SGI_ENV)
1471 osi_Assert((valusema(&avc->vc_rwlock) <= 0)
1472 && (OSI_GET_LOCKID() == avc->vc_rwlockid));
1473 if (length < avc->m.Length) {
1474 vnode_t *vp = (vnode_t *) avc;
1476 osi_Assert(WriteLocked(&avc->lock));
1477 ReleaseWriteLock(&avc->lock);
1479 PTOSSVP(vp, (off_t) length, (off_t) MAXLONG);
1481 ObtainWriteLock(&avc->lock, 67);
1484 /* if writing the file, don't fetch over this value */
1485 afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT, ICL_TYPE_POINTER, avc,
1486 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1487 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1488 avc->m.Length = length;
1489 avc->m.Date = astat->ClientModTime;
1491 avc->m.Owner = astat->Owner;
1492 avc->m.Group = astat->Group;
1493 avc->m.Mode = astat->UnixModeBits;
1494 if (vType(avc) == VREG) {
1495 avc->m.Mode |= S_IFREG;
1496 } else if (vType(avc) == VDIR) {
1497 avc->m.Mode |= S_IFDIR;
1498 } else if (vType(avc) == VLNK) {
1499 avc->m.Mode |= S_IFLNK;
1500 if ((avc->m.Mode & 0111) == 0)
1503 if (avc->states & CForeign) {
1504 struct axscache *ac;
1505 avc->anyAccess = astat->AnonymousAccess;
1507 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1509 * Caller has at least one bit not covered by anonymous, and
1510 * thus may have interesting rights.
1512 * HOWEVER, this is a really bad idea, because any access query
1513 * for bits which aren't covered by anonymous, on behalf of a user
1514 * who doesn't have any special rights, will result in an answer of
1515 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1516 * It's an especially bad idea under Ultrix, since (due to the lack of
1517 * a proper access() call) it must perform several afs_access() calls
1518 * in order to create magic mode bits that vary according to who makes
1519 * the call. In other words, _every_ stat() generates a test for
1522 #endif /* badidea */
1523 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1524 ac->axess = astat->CallerAccess;
1525 else /* not found, add a new one if possible */
1526 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1530 } /*afs_SimpleVStat */
1537 * Store the status info *only* back to the server for a
1541 * avc : Ptr to the vcache entry.
1542 * astatus : Ptr to the status info to store.
1543 * areq : Ptr to the associated vrequest.
1546 * Must be called with a shared lock held on the vnode.
1550 afs_WriteVCache(register struct vcache *avc,
1551 register struct AFSStoreStatus *astatus,
1552 struct vrequest *areq)
1556 struct AFSFetchStatus OutStatus;
1557 struct AFSVolSync tsync;
1558 XSTATS_DECLS AFS_STATCNT(afs_WriteVCache);
1559 afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
1560 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
1563 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1565 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
1568 RXAFS_StoreStatus(tc->id, (struct AFSFid *)&avc->fid.Fid,
1569 astatus, &OutStatus, &tsync);
1574 } while (afs_Analyze
1575 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STORESTATUS,
1576 SHARED_LOCK, NULL));
1578 UpgradeSToWLock(&avc->lock, 20);
1580 /* success, do the changes locally */
1581 afs_SimpleVStat(avc, &OutStatus, areq);
1583 * Update the date, too. SimpleVStat didn't do this, since
1584 * it thought we were doing this after fetching new status
1585 * over a file being written.
1587 avc->m.Date = OutStatus.ClientModTime;
1589 /* failure, set up to check with server next time */
1590 ObtainWriteLock(&afs_xcbhash, 462);
1591 afs_DequeueCallback(avc);
1592 avc->states &= ~(CStatd | CUnique); /* turn off stat valid flag */
1593 ReleaseWriteLock(&afs_xcbhash);
1594 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1595 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
1597 ConvertWToSLock(&avc->lock);
1600 } /*afs_WriteVCache */
1606 * Copy astat block into vcache info
1609 * avc : Ptr to vcache entry.
1610 * astat : Ptr to stat block to copy in.
1611 * areq : Ptr to associated request.
1614 * Must be called under a write lock
1616 * Note: this code may get dataversion and length out of sync if the file has
1617 * been modified. This is less than ideal. I haven't thought about
1618 * it sufficiently to be certain that it is adequate.
1621 afs_ProcessFS(register struct vcache *avc,
1622 register struct AFSFetchStatus *astat, struct vrequest *areq)
1625 AFS_STATCNT(afs_ProcessFS);
1627 #ifdef AFS_64BIT_CLIENT
1628 FillInt64(length, astat->Length_hi, astat->Length);
1629 #else /* AFS_64BIT_CLIENT */
1630 length = astat->Length;
1631 #endif /* AFS_64BIT_CLIENT */
1632 /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
1633 * number for each bulk status request. Under no circumstances
1634 * should afs_DoBulkStat store a sequence number if the new
1635 * length will be ignored when afs_ProcessFS is called with
1636 * new stats. If you change the following conditional then you
1637 * also need to change the conditional in afs_DoBulkStat. */
1639 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1640 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1642 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1644 /* if we're writing or mapping this file, don't fetch over these
1647 afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
1648 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1649 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1650 avc->m.Length = length;
1651 avc->m.Date = astat->ClientModTime;
1653 hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
1654 avc->m.Owner = astat->Owner;
1655 avc->m.Mode = astat->UnixModeBits;
1656 avc->m.Group = astat->Group;
1657 avc->m.LinkCount = astat->LinkCount;
1658 if (astat->FileType == File) {
1659 vSetType(avc, VREG);
1660 avc->m.Mode |= S_IFREG;
1661 } else if (astat->FileType == Directory) {
1662 vSetType(avc, VDIR);
1663 avc->m.Mode |= S_IFDIR;
1664 } else if (astat->FileType == SymbolicLink) {
1665 if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
1666 vSetType(avc, VDIR);
1667 avc->m.Mode |= S_IFDIR;
1669 vSetType(avc, VLNK);
1670 avc->m.Mode |= S_IFLNK;
1672 if ((avc->m.Mode & 0111) == 0) {
1676 avc->anyAccess = astat->AnonymousAccess;
1678 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1680 * Caller has at least one bit not covered by anonymous, and
1681 * thus may have interesting rights.
1683 * HOWEVER, this is a really bad idea, because any access query
1684 * for bits which aren't covered by anonymous, on behalf of a user
1685 * who doesn't have any special rights, will result in an answer of
1686 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1687 * It's an especially bad idea under Ultrix, since (due to the lack of
1688 * a proper access() call) it must perform several afs_access() calls
1689 * in order to create magic mode bits that vary according to who makes
1690 * the call. In other words, _every_ stat() generates a test for
1693 #endif /* badidea */
1695 struct axscache *ac;
1696 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1697 ac->axess = astat->CallerAccess;
1698 else /* not found, add a new one if possible */
1699 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1701 #ifdef AFS_LINUX22_ENV
1702 vcache2inode(avc); /* Set the inode attr cache */
1704 #ifdef AFS_DARWIN_ENV
1705 osi_VM_Setup(avc, 1);
1708 } /*afs_ProcessFS */
1712 afs_RemoteLookup(register struct VenusFid *afid, struct vrequest *areq,
1713 char *name, struct VenusFid *nfid,
1714 struct AFSFetchStatus *OutStatusp,
1715 struct AFSCallBack *CallBackp, struct server **serverp,
1716 struct AFSVolSync *tsyncp)
1720 register struct conn *tc;
1721 struct AFSFetchStatus OutDirStatus;
1722 XSTATS_DECLS if (!name)
1723 name = ""; /* XXX */
1725 tc = afs_Conn(afid, areq, SHARED_LOCK);
1728 *serverp = tc->srvr->server;
1730 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
1733 RXAFS_Lookup(tc->id, (struct AFSFid *)&afid->Fid, name,
1734 (struct AFSFid *)&nfid->Fid, OutStatusp,
1735 &OutDirStatus, CallBackp, tsyncp);
1740 } while (afs_Analyze
1741 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_XLOOKUP, SHARED_LOCK,
1752 * Given a file id and a vrequest structure, fetch the status
1753 * information associated with the file.
1757 * areq : Ptr to associated vrequest structure, specifying the
1758 * user whose authentication tokens will be used.
1759 * avc : caller may already have a vcache for this file, which is
1763 * The cache entry is returned with an increased vrefCount field.
1764 * The entry must be discarded by calling afs_PutVCache when you
1765 * are through using the pointer to the cache entry.
1767 * You should not hold any locks when calling this function, except
1768 * locks on other vcache entries. If you lock more than one vcache
1769 * entry simultaneously, you should lock them in this order:
1771 * 1. Lock all files first, then directories.
1772 * 2. Within a particular type, lock entries in Fid.Vnode order.
1774 * This locking hierarchy is convenient because it allows locking
1775 * of a parent dir cache entry, given a file (to check its access
1776 * control list). It also allows renames to be handled easily by
1777 * locking directories in a constant order.
1778 * NB. NewVCache -> FlushVCache presently (4/10/95) drops the xvcache lock.
1780 /* might have a vcache structure already, which must
1781 * already be held by the caller */
1784 afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
1785 afs_int32 * cached, struct vcache *avc)
1788 afs_int32 code, newvcache = 0;
1789 register struct vcache *tvc;
1793 AFS_STATCNT(afs_GetVCache);
1796 *cached = 0; /* Init just in case */
1798 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1802 ObtainSharedLock(&afs_xvcache, 5);
1804 tvc = afs_FindVCache(afid, &retry, DO_STATS | DO_VLRU);
1806 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1807 ReleaseSharedLock(&afs_xvcache);
1808 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1816 if (tvc->states & CStatd) {
1817 ReleaseSharedLock(&afs_xvcache);
1821 UpgradeSToWLock(&afs_xvcache, 21);
1823 /* no cache entry, better grab one */
1824 tvc = afs_NewVCache(afid, NULL);
1827 ConvertWToSLock(&afs_xvcache);
1828 afs_stats_cmperf.vcacheMisses++;
1831 ReleaseSharedLock(&afs_xvcache);
1833 ObtainWriteLock(&tvc->lock, 54);
1835 if (tvc->states & CStatd) {
1836 #ifdef AFS_LINUX22_ENV
1839 ReleaseWriteLock(&tvc->lock);
1840 #ifdef AFS_DARWIN_ENV
1841 osi_VM_Setup(tvc, 0);
1845 #if defined(AFS_OSF_ENV)
1846 if (afs_IsWired(tvc)) {
1847 ReleaseWriteLock(&tvc->lock);
1850 #endif /* AFS_OSF_ENV */
1852 VOP_LOCK(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY, curproc);
1853 uvm_vnp_uncache(AFSTOV(tvc));
1854 VOP_UNLOCK(AFSTOV(tvc), 0, curproc);
1858 * XXX - I really don't like this. Should try to understand better.
1859 * It seems that sometimes, when we get called, we already hold the
1860 * lock on the vnode (e.g., from afs_getattr via afs_VerifyVCache).
1861 * We can't drop the vnode lock, because that could result in a race.
1862 * Sometimes, though, we get here and don't hold the vnode lock.
1863 * I hate code paths that sometimes hold locks and sometimes don't.
1864 * In any event, the dodge we use here is to check whether the vnode
1865 * is locked, and if it isn't, then we gain and drop it around the call
1866 * to vinvalbuf; otherwise, we leave it alone.
1873 #ifdef AFS_FBSD50_ENV
1874 iheldthelock = VOP_ISLOCKED(vp, curthread);
1876 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
1877 vinvalbuf(vp, V_SAVE, osi_curcred(), curthread, PINOD, 0);
1879 VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
1881 iheldthelock = VOP_ISLOCKED(vp, curproc);
1883 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
1884 vinvalbuf(vp, V_SAVE, osi_curcred(), curproc, PINOD, 0);
1886 VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
1891 ObtainWriteLock(&afs_xcbhash, 464);
1892 tvc->states &= ~CUnique;
1894 afs_DequeueCallback(tvc);
1895 ReleaseWriteLock(&afs_xcbhash);
1897 /* It is always appropriate to throw away all the access rights? */
1898 afs_FreeAllAxs(&(tvc->Access));
1899 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-volume info */
1901 if ((tvp->states & VForeign)) {
1903 tvc->states |= CForeign;
1904 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
1905 && (tvp->rootUnique == afid->Fid.Unique)) {
1909 if (tvp->states & VRO)
1911 if (tvp->states & VBackup)
1912 tvc->states |= CBackup;
1913 /* now copy ".." entry back out of volume structure, if necessary */
1914 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
1916 tvc->mvid = (struct VenusFid *)
1917 osi_AllocSmallSpace(sizeof(struct VenusFid));
1918 *tvc->mvid = tvp->dotdot;
1920 afs_PutVolume(tvp, READ_LOCK);
1924 afs_RemoveVCB(afid);
1926 struct AFSFetchStatus OutStatus;
1928 if (afs_DynrootNewVnode(tvc, &OutStatus)) {
1929 afs_ProcessFS(tvc, &OutStatus, areq);
1930 tvc->states |= CStatd | CUnique;
1933 code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
1938 ReleaseWriteLock(&tvc->lock);
1940 ObtainReadLock(&afs_xvcache);
1942 ReleaseReadLock(&afs_xvcache);
1946 ReleaseWriteLock(&tvc->lock);
1949 } /*afs_GetVCache */
1954 afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
1955 afs_int32 * cached, struct vcache *adp, char *aname)
1957 afs_int32 code, now, newvcache = 0;
1958 struct VenusFid nfid;
1959 register struct vcache *tvc;
1961 struct AFSFetchStatus OutStatus;
1962 struct AFSCallBack CallBack;
1963 struct AFSVolSync tsync;
1964 struct server *serverp = 0;
1968 AFS_STATCNT(afs_GetVCache);
1970 *cached = 0; /* Init just in case */
1972 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1976 ObtainReadLock(&afs_xvcache);
1977 tvc = afs_FindVCache(afid, &retry, DO_STATS /* no vlru */ );
1980 ReleaseReadLock(&afs_xvcache);
1982 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1983 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1987 ObtainReadLock(&tvc->lock);
1989 if (tvc->states & CStatd) {
1993 ReleaseReadLock(&tvc->lock);
1996 tvc->states &= ~CUnique;
1998 ReleaseReadLock(&tvc->lock);
1999 ObtainReadLock(&afs_xvcache);
2003 ReleaseReadLock(&afs_xvcache);
2005 /* lookup the file */
2008 origCBs = afs_allCBs; /* if anything changes, we don't have a cb */
2010 afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
2013 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2017 ObtainSharedLock(&afs_xvcache, 6);
2018 tvc = afs_FindVCache(&nfid, &retry, DO_VLRU /* no xstats now */ );
2020 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2021 ReleaseSharedLock(&afs_xvcache);
2022 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2028 /* no cache entry, better grab one */
2029 UpgradeSToWLock(&afs_xvcache, 22);
2030 tvc = afs_NewVCache(&nfid, serverp);
2032 ConvertWToSLock(&afs_xvcache);
2035 ReleaseSharedLock(&afs_xvcache);
2036 ObtainWriteLock(&tvc->lock, 55);
2038 /* It is always appropriate to throw away all the access rights? */
2039 afs_FreeAllAxs(&(tvc->Access));
2040 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-vol info */
2042 if ((tvp->states & VForeign)) {
2044 tvc->states |= CForeign;
2045 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
2046 && (tvp->rootUnique == afid->Fid.Unique))
2049 if (tvp->states & VRO)
2051 if (tvp->states & VBackup)
2052 tvc->states |= CBackup;
2053 /* now copy ".." entry back out of volume structure, if necessary */
2054 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2056 tvc->mvid = (struct VenusFid *)
2057 osi_AllocSmallSpace(sizeof(struct VenusFid));
2058 *tvc->mvid = tvp->dotdot;
2063 ObtainWriteLock(&afs_xcbhash, 465);
2064 afs_DequeueCallback(tvc);
2065 tvc->states &= ~(CStatd | CUnique);
2066 ReleaseWriteLock(&afs_xcbhash);
2067 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2068 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2070 afs_PutVolume(tvp, READ_LOCK);
2071 ReleaseWriteLock(&tvc->lock);
2072 ObtainReadLock(&afs_xvcache);
2074 ReleaseReadLock(&afs_xvcache);
2078 ObtainWriteLock(&afs_xcbhash, 466);
2079 if (origCBs == afs_allCBs) {
2080 if (CallBack.ExpirationTime) {
2081 tvc->callback = serverp;
2082 tvc->cbExpires = CallBack.ExpirationTime + now;
2083 tvc->states |= CStatd | CUnique;
2084 tvc->states &= ~CBulkFetching;
2085 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvp);
2086 } else if (tvc->states & CRO) {
2087 /* adapt gives us an hour. */
2088 tvc->cbExpires = 3600 + osi_Time();
2089 /*XXX*/ tvc->states |= CStatd | CUnique;
2090 tvc->states &= ~CBulkFetching;
2091 afs_QueueCallback(tvc, CBHash(3600), tvp);
2093 tvc->callback = NULL;
2094 afs_DequeueCallback(tvc);
2095 tvc->states &= ~(CStatd | CUnique);
2096 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2097 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2100 afs_DequeueCallback(tvc);
2101 tvc->states &= ~CStatd;
2102 tvc->states &= ~CUnique;
2103 tvc->callback = NULL;
2104 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2105 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2107 ReleaseWriteLock(&afs_xcbhash);
2109 afs_PutVolume(tvp, READ_LOCK);
2110 afs_ProcessFS(tvc, &OutStatus, areq);
2112 ReleaseWriteLock(&tvc->lock);
2118 afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
2119 afs_int32 * cached, struct volume *tvolp)
2121 afs_int32 code = 0, i, newvcache = 0, haveStatus = 0;
2122 afs_int32 getNewFid = 0;
2124 struct VenusFid nfid;
2125 register struct vcache *tvc;
2126 struct server *serverp = 0;
2127 struct AFSFetchStatus OutStatus;
2128 struct AFSCallBack CallBack;
2129 struct AFSVolSync tsync;
2135 if (!tvolp->rootVnode || getNewFid) {
2136 struct VenusFid tfid;
2139 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2140 origCBs = afs_allCBs; /* ignore InitCallBackState */
2142 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2147 /* ReleaseReadLock(&tvolp->lock); */
2148 ObtainWriteLock(&tvolp->lock, 56);
2149 tvolp->rootVnode = afid->Fid.Vnode = nfid.Fid.Vnode;
2150 tvolp->rootUnique = afid->Fid.Unique = nfid.Fid.Unique;
2151 ReleaseWriteLock(&tvolp->lock);
2152 /* ObtainReadLock(&tvolp->lock);*/
2155 afid->Fid.Vnode = tvolp->rootVnode;
2156 afid->Fid.Unique = tvolp->rootUnique;
2159 ObtainSharedLock(&afs_xvcache, 7);
2161 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2162 if (!FidCmp(&(tvc->fid), afid)) {
2164 /* Grab this vnode, possibly reactivating from the free list */
2165 /* for the present (95.05.25) everything on the hash table is
2166 * definitively NOT in the free list -- at least until afs_reclaim
2167 * can be safely implemented */
2170 vg = vget(AFSTOV(tvc)); /* this bumps ref count */
2174 #endif /* AFS_OSF_ENV */
2179 if (!haveStatus && (!tvc || !(tvc->states & CStatd))) {
2180 /* Mount point no longer stat'd or unknown. FID may have changed. */
2183 AFS_RELE(AFSTOV(tvc));
2187 ReleaseSharedLock(&afs_xvcache);
2192 UpgradeSToWLock(&afs_xvcache, 23);
2193 /* no cache entry, better grab one */
2194 tvc = afs_NewVCache(afid, NULL);
2196 afs_stats_cmperf.vcacheMisses++;
2200 afs_stats_cmperf.vcacheHits++;
2202 /* we already bumped the ref count in the for loop above */
2203 #else /* AFS_OSF_ENV */
2206 UpgradeSToWLock(&afs_xvcache, 24);
2207 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2208 refpanic("GRVC VLRU inconsistent0");
2210 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2211 refpanic("GRVC VLRU inconsistent1");
2213 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2214 refpanic("GRVC VLRU inconsistent2");
2216 QRemove(&tvc->vlruq); /* move to lruq head */
2217 QAdd(&VLRU, &tvc->vlruq);
2218 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2219 refpanic("GRVC VLRU inconsistent3");
2221 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2222 refpanic("GRVC VLRU inconsistent4");
2224 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2225 refpanic("GRVC VLRU inconsistent5");
2230 ReleaseWriteLock(&afs_xvcache);
2232 if (tvc->states & CStatd) {
2236 ObtainReadLock(&tvc->lock);
2237 tvc->states &= ~CUnique;
2238 tvc->callback = NULL; /* redundant, perhaps */
2239 ReleaseReadLock(&tvc->lock);
2242 ObtainWriteLock(&tvc->lock, 57);
2244 /* It is always appropriate to throw away all the access rights? */
2245 afs_FreeAllAxs(&(tvc->Access));
2248 tvc->states |= CForeign;
2249 if (tvolp->states & VRO)
2251 if (tvolp->states & VBackup)
2252 tvc->states |= CBackup;
2253 /* now copy ".." entry back out of volume structure, if necessary */
2254 if (newvcache && (tvolp->rootVnode == afid->Fid.Vnode)
2255 && (tvolp->rootUnique == afid->Fid.Unique)) {
2258 if (tvc->mvstat == 2 && tvolp->dotdot.Fid.Volume != 0) {
2260 tvc->mvid = (struct VenusFid *)
2261 osi_AllocSmallSpace(sizeof(struct VenusFid));
2262 *tvc->mvid = tvolp->dotdot;
2266 afs_RemoveVCB(afid);
2269 struct VenusFid tfid;
2272 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2273 origCBs = afs_allCBs; /* ignore InitCallBackState */
2275 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2280 ObtainWriteLock(&afs_xcbhash, 467);
2281 afs_DequeueCallback(tvc);
2282 tvc->callback = NULL;
2283 tvc->states &= ~(CStatd | CUnique);
2284 ReleaseWriteLock(&afs_xcbhash);
2285 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2286 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2287 ReleaseWriteLock(&tvc->lock);
2288 ObtainReadLock(&afs_xvcache);
2290 ReleaseReadLock(&afs_xvcache);
2294 ObtainWriteLock(&afs_xcbhash, 468);
2295 if (origCBs == afs_allCBs) {
2296 tvc->states |= CTruth;
2297 tvc->callback = serverp;
2298 if (CallBack.ExpirationTime != 0) {
2299 tvc->cbExpires = CallBack.ExpirationTime + start;
2300 tvc->states |= CStatd;
2301 tvc->states &= ~CBulkFetching;
2302 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvolp);
2303 } else if (tvc->states & CRO) {
2304 /* adapt gives us an hour. */
2305 tvc->cbExpires = 3600 + osi_Time();
2306 /*XXX*/ tvc->states |= CStatd;
2307 tvc->states &= ~CBulkFetching;
2308 afs_QueueCallback(tvc, CBHash(3600), tvolp);
2311 afs_DequeueCallback(tvc);
2312 tvc->callback = NULL;
2313 tvc->states &= ~(CStatd | CUnique);
2314 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2315 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2317 ReleaseWriteLock(&afs_xcbhash);
2318 afs_ProcessFS(tvc, &OutStatus, areq);
2320 ReleaseWriteLock(&tvc->lock);
2327 * must be called with avc write-locked
2328 * don't absolutely have to invalidate the hint unless the dv has
2329 * changed, but be sure to get it right else there will be consistency bugs.
2332 afs_FetchStatus(struct vcache * avc, struct VenusFid * afid,
2333 struct vrequest * areq, struct AFSFetchStatus * Outsp)
2336 afs_uint32 start = 0;
2337 register struct conn *tc;
2338 struct AFSCallBack CallBack;
2339 struct AFSVolSync tsync;
2340 struct volume *volp;
2343 tc = afs_Conn(afid, areq, SHARED_LOCK);
2344 avc->quick.stamp = 0;
2345 avc->h1.dchint = NULL; /* invalidate hints */
2347 avc->callback = tc->srvr->server;
2349 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
2352 RXAFS_FetchStatus(tc->id, (struct AFSFid *)&afid->Fid, Outsp,
2360 } while (afs_Analyze
2361 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS,
2362 SHARED_LOCK, NULL));
2365 afs_ProcessFS(avc, Outsp, areq);
2366 volp = afs_GetVolume(afid, areq, READ_LOCK);
2367 ObtainWriteLock(&afs_xcbhash, 469);
2368 avc->states |= CTruth;
2369 if (avc->callback /* check for race */ ) {
2370 if (CallBack.ExpirationTime != 0) {
2371 avc->cbExpires = CallBack.ExpirationTime + start;
2372 avc->states |= CStatd;
2373 avc->states &= ~CBulkFetching;
2374 afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
2375 } else if (avc->states & CRO) { /* ordinary callback on a read-only volume -- AFS 3.2 style */
2376 avc->cbExpires = 3600 + start;
2377 avc->states |= CStatd;
2378 avc->states &= ~CBulkFetching;
2379 afs_QueueCallback(avc, CBHash(3600), volp);
2381 afs_DequeueCallback(avc);
2382 avc->callback = NULL;
2383 avc->states &= ~(CStatd | CUnique);
2384 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2385 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2388 afs_DequeueCallback(avc);
2389 avc->callback = NULL;
2390 avc->states &= ~(CStatd | CUnique);
2391 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2392 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2394 ReleaseWriteLock(&afs_xcbhash);
2396 afs_PutVolume(volp, READ_LOCK);
2398 /* used to undo the local callback, but that's too extreme.
2399 * There are plenty of good reasons that fetchstatus might return
2400 * an error, such as EPERM. If we have the vnode cached, statd,
2401 * with callback, might as well keep track of the fact that we
2402 * don't have access...
2404 if (code == EPERM || code == EACCES) {
2405 struct axscache *ac;
2406 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
2408 else /* not found, add a new one if possible */
2409 afs_AddAxs(avc->Access, areq->uid, 0);
2420 * Stuff some information into the vcache for the given file.
2423 * afid : File in question.
2424 * OutStatus : Fetch status on the file.
2425 * CallBack : Callback info.
2426 * tc : RPC connection involved.
2427 * areq : vrequest involved.
2430 * Nothing interesting.
2433 afs_StuffVcache(register struct VenusFid *afid,
2434 struct AFSFetchStatus *OutStatus,
2435 struct AFSCallBack *CallBack, register struct conn *tc,
2436 struct vrequest *areq)
2438 register afs_int32 code, i, newvcache = 0;
2439 register struct vcache *tvc;
2440 struct AFSVolSync tsync;
2442 struct axscache *ac;
2445 AFS_STATCNT(afs_StuffVcache);
2446 #ifdef IFS_VCACHECOUNT
2451 ObtainSharedLock(&afs_xvcache, 8);
2453 tvc = afs_FindVCache(afid, &retry, DO_VLRU /* no stats */ );
2455 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2456 ReleaseSharedLock(&afs_xvcache);
2457 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2463 /* no cache entry, better grab one */
2464 UpgradeSToWLock(&afs_xvcache, 25);
2465 tvc = afs_NewVCache(afid, NULL);
2467 ConvertWToSLock(&afs_xvcache);
2470 ReleaseSharedLock(&afs_xvcache);
2471 ObtainWriteLock(&tvc->lock, 58);
2473 tvc->states &= ~CStatd;
2474 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2475 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2477 /* Is it always appropriate to throw away all the access rights? */
2478 afs_FreeAllAxs(&(tvc->Access));
2480 /*Copy useful per-volume info */
2481 tvp = afs_GetVolume(afid, areq, READ_LOCK);
2483 if (newvcache && (tvp->states & VForeign))
2484 tvc->states |= CForeign;
2485 if (tvp->states & VRO)
2487 if (tvp->states & VBackup)
2488 tvc->states |= CBackup;
2490 * Now, copy ".." entry back out of volume structure, if
2493 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2495 tvc->mvid = (struct VenusFid *)
2496 osi_AllocSmallSpace(sizeof(struct VenusFid));
2497 *tvc->mvid = tvp->dotdot;
2500 /* store the stat on the file */
2501 afs_RemoveVCB(afid);
2502 afs_ProcessFS(tvc, OutStatus, areq);
2503 tvc->callback = tc->srvr->server;
2505 /* we use osi_Time twice below. Ideally, we would use the time at which
2506 * the FetchStatus call began, instead, but we don't have it here. So we
2507 * make do with "now". In the CRO case, it doesn't really matter. In
2508 * the other case, we hope that the difference between "now" and when the
2509 * call actually began execution on the server won't be larger than the
2510 * padding which the server keeps. Subtract 1 second anyway, to be on
2511 * the safe side. Can't subtract more because we don't know how big
2512 * ExpirationTime is. Possible consistency problems may arise if the call
2513 * timeout period becomes longer than the server's expiration padding. */
2514 ObtainWriteLock(&afs_xcbhash, 470);
2515 if (CallBack->ExpirationTime != 0) {
2516 tvc->cbExpires = CallBack->ExpirationTime + osi_Time() - 1;
2517 tvc->states |= CStatd;
2518 tvc->states &= ~CBulkFetching;
2519 afs_QueueCallback(tvc, CBHash(CallBack->ExpirationTime), tvp);
2520 } else if (tvc->states & CRO) {
2521 /* old-fashioned AFS 3.2 style */
2522 tvc->cbExpires = 3600 + osi_Time();
2523 /*XXX*/ tvc->states |= CStatd;
2524 tvc->states &= ~CBulkFetching;
2525 afs_QueueCallback(tvc, CBHash(3600), tvp);
2527 afs_DequeueCallback(tvc);
2528 tvc->callback = NULL;
2529 tvc->states &= ~(CStatd | CUnique);
2530 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2531 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2533 ReleaseWriteLock(&afs_xcbhash);
2535 afs_PutVolume(tvp, READ_LOCK);
2537 /* look in per-pag cache */
2538 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, areq->uid)))
2539 ac->axess = OutStatus->CallerAccess; /* substitute pags */
2540 else /* not found, add a new one if possible */
2541 afs_AddAxs(tvc->Access, areq->uid, OutStatus->CallerAccess);
2543 ReleaseWriteLock(&tvc->lock);
2544 afs_Trace4(afs_iclSetp, CM_TRACE_STUFFVCACHE, ICL_TYPE_POINTER, tvc,
2545 ICL_TYPE_POINTER, tvc->callback, ICL_TYPE_INT32,
2546 tvc->cbExpires, ICL_TYPE_INT32, tvc->cbExpires - osi_Time());
2548 * Release ref count... hope this guy stays around...
2551 } /*afs_StuffVcache */
2558 * Decrements the reference count on a cache entry.
2561 * avc : Pointer to the cache entry to decrement.
2564 * Nothing interesting.
2567 afs_PutVCache(register struct vcache *avc)
2569 AFS_STATCNT(afs_PutVCache);
2571 * Can we use a read lock here?
2573 ObtainReadLock(&afs_xvcache);
2575 ReleaseReadLock(&afs_xvcache);
2576 } /*afs_PutVCache */
2582 * Find a vcache entry given a fid.
2585 * afid : Pointer to the fid whose cache entry we desire.
2586 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2587 * unlock the vnode, and try again.
2588 * flags: bit 1 to specify whether to compute hit statistics. Not
2589 * set if FindVCache is called as part of internal bookkeeping.
2592 * Must be called with the afs_xvcache lock at least held at
2593 * the read level. In order to do the VLRU adjustment, the xvcache lock
2594 * must be shared-- we upgrade it here.
2598 afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, afs_int32 flag)
2601 register struct vcache *tvc;
2604 AFS_STATCNT(afs_FindVCache);
2607 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2608 if (FidMatches(afid, tvc)) {
2610 /* Grab this vnode, possibly reactivating from the free list */
2613 vg = vget(AFSTOV(tvc));
2617 #endif /* AFS_OSF_ENV */
2622 /* should I have a read lock on the vnode here? */
2626 #if !defined(AFS_OSF_ENV)
2627 osi_vnhold(tvc, retry); /* already held, above */
2628 if (retry && *retry)
2632 * only move to front of vlru if we have proper vcache locking)
2634 if (flag & DO_VLRU) {
2635 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2636 refpanic("FindVC VLRU inconsistent1");
2638 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2639 refpanic("FindVC VLRU inconsistent1");
2641 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2642 refpanic("FindVC VLRU inconsistent2");
2644 UpgradeSToWLock(&afs_xvcache, 26);
2645 QRemove(&tvc->vlruq);
2646 QAdd(&VLRU, &tvc->vlruq);
2647 ConvertWToSLock(&afs_xvcache);
2648 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2649 refpanic("FindVC VLRU inconsistent1");
2651 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2652 refpanic("FindVC VLRU inconsistent2");
2654 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2655 refpanic("FindVC VLRU inconsistent3");
2661 if (flag & DO_STATS) {
2663 afs_stats_cmperf.vcacheHits++;
2665 afs_stats_cmperf.vcacheMisses++;
2666 if (afs_IsPrimaryCellNum(afid->Cell))
2667 afs_stats_cmperf.vlocalAccesses++;
2669 afs_stats_cmperf.vremoteAccesses++;
2671 #ifdef AFS_LINUX22_ENV
2672 if (tvc && (tvc->states & CStatd))
2673 vcache2inode(tvc); /* mainly to reset i_nlink */
2675 #ifdef AFS_DARWIN_ENV
2677 osi_VM_Setup(tvc, 0);
2680 } /*afs_FindVCache */
2686 * Find a vcache entry given a fid. Does a wildcard match on what we
2687 * have for the fid. If more than one entry, don't return anything.
2690 * avcp : Fill in pointer if we found one and only one.
2691 * afid : Pointer to the fid whose cache entry we desire.
2692 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2693 * unlock the vnode, and try again.
2694 * flags: bit 1 to specify whether to compute hit statistics. Not
2695 * set if FindVCache is called as part of internal bookkeeping.
2698 * Must be called with the afs_xvcache lock at least held at
2699 * the read level. In order to do the VLRU adjustment, the xvcache lock
2700 * must be shared-- we upgrade it here.
2703 * number of matches found.
2706 int afs_duplicate_nfs_fids = 0;
2709 afs_NFSFindVCache(struct vcache **avcp, struct VenusFid *afid)
2711 register struct vcache *tvc;
2713 afs_int32 count = 0;
2714 struct vcache *found_tvc = NULL;
2716 AFS_STATCNT(afs_FindVCache);
2718 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2722 ObtainSharedLock(&afs_xvcache, 331);
2725 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2726 /* Match only on what we have.... */
2727 if (((tvc->fid.Fid.Vnode & 0xffff) == afid->Fid.Vnode)
2728 && (tvc->fid.Fid.Volume == afid->Fid.Volume)
2729 && ((tvc->fid.Fid.Unique & 0xffffff) == afid->Fid.Unique)
2730 && (tvc->fid.Cell == afid->Cell)) {
2732 /* Grab this vnode, possibly reactivating from the free list */
2735 vg = vget(AFSTOV(tvc));
2738 /* This vnode no longer exists. */
2741 #endif /* AFS_OSF_ENV */
2746 /* Drop our reference counts. */
2748 vrele(AFSTOV(found_tvc));
2750 afs_duplicate_nfs_fids++;
2751 ReleaseSharedLock(&afs_xvcache);
2759 /* should I have a read lock on the vnode here? */
2761 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2762 afs_int32 retry = 0;
2763 osi_vnhold(tvc, &retry);
2766 found_tvc = (struct vcache *)0;
2767 ReleaseSharedLock(&afs_xvcache);
2768 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2772 #if !defined(AFS_OSF_ENV)
2773 osi_vnhold(tvc, (int *)0); /* already held, above */
2777 * We obtained the xvcache lock above.
2779 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2780 refpanic("FindVC VLRU inconsistent1");
2782 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2783 refpanic("FindVC VLRU inconsistent1");
2785 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2786 refpanic("FindVC VLRU inconsistent2");
2788 UpgradeSToWLock(&afs_xvcache, 568);
2789 QRemove(&tvc->vlruq);
2790 QAdd(&VLRU, &tvc->vlruq);
2791 ConvertWToSLock(&afs_xvcache);
2792 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2793 refpanic("FindVC VLRU inconsistent1");
2795 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2796 refpanic("FindVC VLRU inconsistent2");
2798 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2799 refpanic("FindVC VLRU inconsistent3");
2805 afs_stats_cmperf.vcacheHits++;
2807 afs_stats_cmperf.vcacheMisses++;
2808 if (afs_IsPrimaryCellNum(afid->Cell))
2809 afs_stats_cmperf.vlocalAccesses++;
2811 afs_stats_cmperf.vremoteAccesses++;
2813 *avcp = tvc; /* May be null */
2815 ReleaseSharedLock(&afs_xvcache);
2816 return (tvc ? 1 : 0);
2818 } /*afs_NFSFindVCache */
2826 * Initialize vcache related variables
2829 afs_vcacheInit(int astatSize)
2831 register struct vcache *tvp;
2833 #if defined(AFS_OSF_ENV)
2834 if (!afs_maxvcount) {
2835 #if defined(AFS_OSF30_ENV)
2836 afs_maxvcount = max_vnodes / 2; /* limit ourselves to half the total */
2838 afs_maxvcount = nvnode / 2; /* limit ourselves to half the total */
2840 if (astatSize < afs_maxvcount) {
2841 afs_maxvcount = astatSize;
2844 #else /* AFS_OSF_ENV */
2848 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2849 LOCK_INIT(&afs_xvcb, "afs_xvcb");
2851 #if !defined(AFS_OSF_ENV)
2852 /* Allocate and thread the struct vcache entries */
2853 tvp = (struct vcache *)afs_osi_Alloc(astatSize * sizeof(struct vcache));
2854 memset((char *)tvp, 0, sizeof(struct vcache) * astatSize);
2856 Initial_freeVCList = tvp;
2857 freeVCList = &(tvp[0]);
2858 for (i = 0; i < astatSize - 1; i++) {
2859 tvp[i].nextfree = &(tvp[i + 1]);
2861 tvp[astatSize - 1].nextfree = NULL;
2862 #ifdef KERNEL_HAVE_PIN
2863 pin((char *)tvp, astatSize * sizeof(struct vcache)); /* XXX */
2868 #if defined(AFS_SGI_ENV)
2869 for (i = 0; i < astatSize; i++) {
2870 char name[METER_NAMSZ];
2871 struct vcache *tvc = &tvp[i];
2873 tvc->v.v_number = ++afsvnumbers;
2874 tvc->vc_rwlockid = OSI_NO_LOCKID;
2875 initnsema(&tvc->vc_rwlock, 1,
2876 makesname(name, "vrw", tvc->v.v_number));
2877 #ifndef AFS_SGI53_ENV
2878 initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
2880 #ifndef AFS_SGI62_ENV
2881 initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
2882 #endif /* AFS_SGI62_ENV */
2896 shutdown_vcache(void)
2899 struct afs_cbr *tsp, *nsp;
2901 * XXX We may potentially miss some of the vcaches because if when there're no
2902 * free vcache entries and all the vcache entries are active ones then we allocate
2903 * an additional one - admittedly we almost never had that occur.
2907 register struct afs_q *tq, *uq;
2908 register struct vcache *tvc;
2909 for (tq = VLRU.prev; tq != &VLRU; tq = uq) {
2913 osi_FreeSmallSpace(tvc->mvid);
2914 tvc->mvid = (struct VenusFid *)0;
2917 aix_gnode_rele(AFSTOV(tvc));
2919 if (tvc->linkData) {
2920 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2925 * Also free the remaining ones in the Cache
2927 for (i = 0; i < VCSIZE; i++) {
2928 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2930 osi_FreeSmallSpace(tvc->mvid);
2931 tvc->mvid = (struct VenusFid *)0;
2935 afs_osi_Free(tvc->v.v_gnode, sizeof(struct gnode));
2936 #ifdef AFS_AIX32_ENV
2939 vms_delete(tvc->segid);
2941 tvc->segid = tvc->vmh = NULL;
2943 osi_Panic("flushVcache: vm race");
2951 #if defined(AFS_SUN5_ENV)
2957 if (tvc->linkData) {
2958 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2962 afs_FreeAllAxs(&(tvc->Access));
2968 * Free any leftover callback queue
2970 for (tsp = afs_cbrSpace; tsp; tsp = nsp) {
2972 afs_osi_Free((char *)tsp, AFS_NCBRS * sizeof(struct afs_cbr));
2976 #if !defined(AFS_OSF_ENV)
2977 afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2979 #ifdef KERNEL_HAVE_PIN
2980 unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2982 #if !defined(AFS_OSF_ENV)
2983 freeVCList = Initial_freeVCList = 0;
2985 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2986 LOCK_INIT(&afs_xvcb, "afs_xvcb");