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 callBacks[0].CallBackType = CB_EXCLUSIVE;
369 for (safety3 = 0; safety3 < MAXHOSTS * 2; safety3++) {
370 tc = afs_ConnByHost(tsp, tsp->cell->fsport,
371 tsp->cell->cellNum, &treq, 0,
375 (AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
378 RXAFS_GiveUpCallBacks(tc->id, &fidArray,
386 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK,
391 /* ignore return code, since callbacks may have
392 * been returned anyway, we shouldn't leave them
393 * around to be returned again.
395 * Next, see if we are done with this server, and if so,
396 * break to deal with the next one.
402 /* if to flush full buffer */
403 /* if we make it here, we have an entry at the head of cbrs,
404 * which we should copy to the file ID array and then free.
407 tfids[tcount++] = tcbrp->fid;
408 tsp->cbrs = tcbrp->next;
410 } /* while loop for this one server */
411 if (safety2 > afs_cacheStats) {
412 afs_warn("possible internal error afs_flushVCBs (%d)\n",
415 } /* for loop for this hash chain */
416 } /* loop through all hash chains */
417 if (safety1 > afs_totalServers + 2) {
419 ("AFS internal error (afs_flushVCBs) (%d > %d), continuing...\n",
420 safety1, afs_totalServers + 2);
422 osi_Panic("afs_flushVCBS safety1");
425 ReleaseReadLock(&afs_xserver);
427 MReleaseWriteLock(&afs_xvcb);
428 afs_osi_Free(tfids, sizeof(struct AFSFid) * AFS_MAXCBRSCALL);
436 * Queue a callback on the given fid.
442 * Locks the xvcb lock.
443 * Called when the xvcache lock is already held.
447 afs_QueueVCB(struct vcache *avc)
449 register struct server *tsp;
450 register struct afs_cbr *tcbp;
452 AFS_STATCNT(afs_QueueVCB);
453 /* The callback is really just a struct server ptr. */
454 tsp = (struct server *)(avc->callback);
456 /* we now have a pointer to the server, so we just allocate
457 * a queue entry and queue it.
459 MObtainWriteLock(&afs_xvcb, 274);
460 tcbp = afs_AllocCBR();
461 tcbp->fid = avc->fid.Fid;
462 tcbp->next = tsp->cbrs;
465 /* now release locks and return */
466 MReleaseWriteLock(&afs_xvcb);
475 * Remove a queued callback by looking through all the servers
476 * to see if any have this callback queued.
479 * afid: The fid we want cleansed of queued callbacks.
482 * Locks xvcb and xserver locks.
483 * Typically called with xdcache, xvcache and/or individual vcache
488 afs_RemoveVCB(struct VenusFid *afid)
491 register struct server *tsp;
492 register struct afs_cbr *tcbrp;
493 struct afs_cbr **lcbrpp;
495 AFS_STATCNT(afs_RemoveVCB);
496 MObtainWriteLock(&afs_xvcb, 275);
497 ObtainReadLock(&afs_xserver);
498 for (i = 0; i < NSERVERS; i++) {
499 for (tsp = afs_servers[i]; tsp; tsp = tsp->next) {
500 /* if cell is known, and is wrong, then skip this server */
501 if (tsp->cell && tsp->cell->cellNum != afid->Cell)
505 * Otherwise, iterate through file IDs we're sending to the
508 lcbrpp = &tsp->cbrs; /* first queued return callback */
509 for (tcbrp = *lcbrpp; tcbrp;
510 lcbrpp = &tcbrp->next, tcbrp = *lcbrpp) {
511 if (afid->Fid.Volume == tcbrp->fid.Volume
512 && afid->Fid.Unique == tcbrp->fid.Unique
513 && afid->Fid.Vnode == tcbrp->fid.Vnode) {
514 *lcbrpp = tcbrp->next; /* unthread from list */
522 ReleaseReadLock(&afs_xserver);
523 MReleaseWriteLock(&afs_xvcb);
527 #if defined(AFS_LINUX22_ENV) && !defined(AFS_LINUX26_ENV)
530 __shrink_dcache_parent(struct dentry *parent)
532 struct dentry *this_parent = parent;
533 struct list_head *next;
535 LIST_HEAD(afs_dentry_unused);
538 next = this_parent->d_subdirs.next;
540 while (next != &this_parent->d_subdirs) {
541 struct list_head *tmp = next;
542 struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
544 if (!DCOUNT(dentry)) {
545 list_del(&dentry->d_lru);
546 list_add(&dentry->d_lru, afs_dentry_unused.prev);
550 * Descend a level if the d_subdirs list is non-empty.
552 if (!list_empty(&dentry->d_subdirs)) {
553 this_parent = dentry;
558 * All done at this level ... ascend and resume the search.
560 if (this_parent != parent) {
561 next = this_parent->d_child.next;
562 this_parent = this_parent->d_parent;
567 struct dentry *dentry;
568 struct list_head *tmp;
570 tmp = afs_dentry_unused.prev;
572 if (tmp == &afs_dentry_unused)
574 #ifdef AFS_LINUX24_ENV
579 #endif /* AFS_LINUX24_ENV */
580 dentry = list_entry(tmp, struct dentry, d_lru);
582 #ifdef AFS_LINUX24_ENV
583 /* Unused dentry with a count? */
588 #ifdef AFS_LINUX24_ENV
589 list_del_init(&dentry->d_hash); /* d_drop */
591 list_del(&dentry->d_hash);
592 INIT_LIST_HEAD(&dentry->d_hash);
593 #endif /* AFS_LINUX24_ENV */
602 /* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
603 * children of the dentry
605 * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
606 * AFS_GLOCK, so it can call dput, which may call iput, but
607 * keeps afs_xvcache exclusively.
609 * Tree traversal algorithm from fs/dcache.c: select_parent()
612 afs_TryFlushDcacheChildren(struct vcache *tvc)
614 struct inode *ip = AFSTOI(tvc);
615 struct dentry *this_parent;
616 struct list_head *next;
617 struct list_head *cur;
618 struct list_head *head = &ip->i_dentry;
619 struct dentry *dentry;
623 #ifndef old_vcache_scheme
626 while ((cur = cur->next) != head) {
627 dentry = list_entry(cur, struct dentry, d_alias);
629 afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN,
630 ICL_TYPE_POINTER, ip, ICL_TYPE_STRING,
631 dentry->d_parent->d_name.name, ICL_TYPE_STRING,
632 dentry->d_name.name);
634 if (!list_empty(&dentry->d_hash) && !list_empty(&dentry->d_subdirs))
635 __shrink_dcache_parent(dentry);
637 if (!DCOUNT(dentry)) {
639 #ifdef AFS_LINUX24_ENV
640 list_del_init(&dentry->d_hash); /* d_drop */
642 list_del(&dentry->d_hash);
643 INIT_LIST_HEAD(&dentry->d_hash);
644 #endif /* AFS_LINUX24_ENV */
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 (!DCOUNT(dentry)) {
677 #endif /* AFS_LINUX22_ENV && !AFS_LINUX26_ENV */
683 * This routine is responsible for allocating a new cache entry
684 * from the free list. It formats the cache entry and inserts it
685 * into the appropriate hash tables. It must be called with
686 * afs_xvcache write-locked so as to prevent several processes from
687 * trying to create a new cache entry simultaneously.
690 * afid : The file id of the file whose cache entry is being
693 /* LOCK: afs_NewVCache afs_xvcache W */
695 afs_NewVCache(struct VenusFid *afid, struct server *serverp)
699 afs_int32 anumber = VCACHE_FREE;
701 struct gnode *gnodepnt;
704 struct vm_info *vm_info_ptr;
705 #endif /* AFS_MACH_ENV */
708 #endif /* AFS_OSF_ENV */
709 struct afs_q *tq, *uq;
712 AFS_STATCNT(afs_NewVCache);
715 if (afs_vcount >= afs_maxvcount) {
718 * If we are using > 33 % of the total system vnodes for AFS vcache
719 * entries or we are using the maximum number of vcache entries,
720 * then free some. (if our usage is > 33% we should free some, if
721 * our usage is > afs_maxvcount, set elsewhere to 0.5*nvnode,
722 * we _must_ free some -- no choice).
724 if (((3 * afs_vcount) > nvnode) || (afs_vcount >= afs_maxvcount)) {
726 struct afs_q *tq, *uq;
731 for (tq = VLRU.prev; tq != &VLRU && anumber > 0; tq = uq) {
734 if (tvc->states & CVFlushed)
735 refpanic("CVFlushed on VLRU");
736 else if (i++ > afs_maxvcount)
737 refpanic("Exceeded pool of AFS vnodes(VLRU cycle?)");
738 else if (QNext(uq) != tq)
739 refpanic("VLRU inconsistent");
740 else if (VREFCOUNT(tvc) < 1)
741 refpanic("refcnt 0 on VLRU");
743 if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
744 && (tvc->states & CUnlinkedDel) == 0) {
745 code = afs_FlushVCache(tvc, &fv_slept);
752 continue; /* start over - may have raced. */
758 if (anumber == VCACHE_FREE) {
759 printf("NewVCache: warning none freed, using %d of %d\n",
760 afs_vcount, afs_maxvcount);
761 if (afs_vcount >= afs_maxvcount) {
762 osi_Panic("NewVCache - none freed");
763 /* XXX instead of panicing, should do afs_maxvcount++
764 * and magic up another one */
770 if (getnewvnode(MOUNT_AFS, &Afs_vnodeops, &nvc)) {
771 /* What should we do ???? */
772 osi_Panic("afs_NewVCache: no more vnodes");
777 tvc->nextfree = NULL;
779 #else /* AFS_OSF_ENV */
780 /* pull out a free cache entry */
783 for (tq = VLRU.prev; (anumber > 0) && (tq != &VLRU); tq = uq) {
787 if (tvc->states & CVFlushed) {
788 refpanic("CVFlushed on VLRU");
789 } else if (i++ > 2 * afs_cacheStats) { /* even allowing for a few xallocs... */
790 refpanic("Increase -stat parameter of afsd(VLRU cycle?)");
791 } else if (QNext(uq) != tq) {
792 refpanic("VLRU inconsistent");
794 #ifdef AFS_DARWIN_ENV
795 if (tvc->opens == 0 && ((tvc->states & CUnlinkedDel) == 0)
796 && VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
797 osi_VM_TryReclaim(tvc, &fv_slept);
801 continue; /* start over - may have raced. */
804 #elif defined(AFS_LINUX22_ENV)
805 if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0) {
806 #if defined(AFS_LINUX26_ENV)
808 d_prune_aliases(AFSTOI(tvc));
811 afs_TryFlushDcacheChildren(tvc);
816 if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
817 && (tvc->states & CUnlinkedDel) == 0) {
818 #if defined(AFS_XBSD_ENV)
820 * vgone() reclaims the vnode, which calls afs_FlushVCache(),
821 * then it puts the vnode on the free list.
822 * If we don't do this we end up with a cleaned vnode that's
823 * not on the free list.
824 * XXX assume FreeBSD is the same for now.
829 code = afs_FlushVCache(tvc, &fv_slept);
837 continue; /* start over - may have raced. */
845 /* none free, making one is better than a panic */
846 afs_stats_cmperf.vcacheXAllocs++; /* count in case we have a leak */
847 tvc = (struct vcache *)afs_osi_Alloc(sizeof(struct vcache));
848 #ifdef KERNEL_HAVE_PIN
849 pin((char *)tvc, sizeof(struct vcache)); /* XXX */
852 /* In case it still comes here we need to fill this */
853 tvc->v.v_vm_info = VM_INFO_NULL;
854 vm_info_init(tvc->v.v_vm_info);
855 /* perhaps we should also do close_flush on non-NeXT mach systems;
856 * who knows; we don't currently have the sources.
858 #endif /* AFS_MACH_ENV */
859 #if defined(AFS_SGI_ENV)
861 char name[METER_NAMSZ];
862 memset(tvc, 0, sizeof(struct vcache));
863 tvc->v.v_number = ++afsvnumbers;
864 tvc->vc_rwlockid = OSI_NO_LOCKID;
865 initnsema(&tvc->vc_rwlock, 1,
866 makesname(name, "vrw", tvc->v.v_number));
867 #ifndef AFS_SGI53_ENV
868 initnsema(&tvc->v.v_sync, 0,
869 makesname(name, "vsy", tvc->v.v_number));
871 #ifndef AFS_SGI62_ENV
872 initnlock(&tvc->v.v_lock,
873 makesname(name, "vlk", tvc->v.v_number));
876 #endif /* AFS_SGI_ENV */
878 tvc = freeVCList; /* take from free list */
879 freeVCList = tvc->nextfree;
880 tvc->nextfree = NULL;
882 #endif /* AFS_OSF_ENV */
885 vm_info_ptr = tvc->v.v_vm_info;
886 #endif /* AFS_MACH_ENV */
888 #if defined(AFS_XBSD_ENV)
890 panic("afs_NewVCache(): free vcache with vnode attached");
893 #if !defined(AFS_SGI_ENV) && !defined(AFS_OSF_ENV)
894 memset((char *)tvc, 0, sizeof(struct vcache));
899 RWLOCK_INIT(&tvc->lock, "vcache lock");
900 #if defined(AFS_SUN5_ENV)
901 RWLOCK_INIT(&tvc->vlock, "vcache vlock");
902 #endif /* defined(AFS_SUN5_ENV) */
905 tvc->v.v_vm_info = vm_info_ptr;
906 tvc->v.v_vm_info->pager = MEMORY_OBJECT_NULL;
907 #endif /* AFS_MACH_ENV */
910 afs_nbsd_getnewvnode(tvc); /* includes one refcount */
912 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
919 #ifdef AFS_FBSD50_ENV
920 if (getnewvnode(MOUNT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
922 if (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &vp))
924 panic("afs getnewvnode"); /* can't happen */
926 if (tvc->v != NULL) {
927 /* I'd like to know if this ever happens...
928 We don't drop global for the rest of this function,
929 so if we do lose the race, the other thread should
930 have found the same vnode and finished initializing
931 the vcache entry. Is it conceivable that this vcache
932 entry could be recycled during this interval? If so,
933 then there probably needs to be some sort of additional
934 mutual exclusion (an Embryonic flag would suffice).
936 printf("afs_NewVCache: lost the race\n");
940 tvc->v->v_data = tvc;
941 lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
944 tvc->parentVnode = 0;
946 tvc->linkData = NULL;
949 tvc->execsOrWriters = 0;
953 tvc->last_looker = 0;
955 tvc->asynchrony = -1;
957 afs_symhint_inval(tvc);
959 tvc->flushDV.low = tvc->flushDV.high = AFS_MAXDV;
962 tvc->truncPos = AFS_NOTRUNC; /* don't truncate until we need to */
963 hzero(tvc->m.DataVersion); /* in case we copy it into flushDV */
964 #if defined(AFS_LINUX22_ENV)
966 struct inode *ip = AFSTOI(tvc);
967 struct address_space *mapping = &ip->i_data;
969 #if defined(AFS_LINUX26_ENV)
972 sema_init(&ip->i_sem, 1);
973 INIT_LIST_HEAD(&ip->i_hash);
974 INIT_LIST_HEAD(&ip->i_dentry);
975 #if defined(AFS_LINUX24_ENV)
976 sema_init(&ip->i_zombie, 1);
977 init_waitqueue_head(&ip->i_wait);
978 spin_lock_init(&ip->i_data.i_shared_lock);
979 #ifdef STRUCT_ADDRESS_SPACE_HAS_PAGE_LOCK
980 spin_lock_init(&ip->i_data.page_lock);
982 INIT_LIST_HEAD(&ip->i_data.clean_pages);
983 INIT_LIST_HEAD(&ip->i_data.dirty_pages);
984 INIT_LIST_HEAD(&ip->i_data.locked_pages);
985 INIT_LIST_HEAD(&ip->i_dirty_buffers);
986 #ifdef STRUCT_INODE_HAS_I_DIRTY_DATA_BUFFERS
987 INIT_LIST_HEAD(&ip->i_dirty_data_buffers);
989 #ifdef STRUCT_INODE_HAS_I_DEVICES
990 INIT_LIST_HEAD(&ip->i_devices);
992 #ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
993 init_rwsem(&ip->i_truncate_sem);
995 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
996 init_rwsem(&ip->i_alloc_sem);
999 #else /* AFS_LINUX22_ENV */
1000 sema_init(&ip->i_atomic_write, 1);
1001 init_waitqueue(&ip->i_wait);
1005 #if defined(AFS_LINUX24_ENV)
1007 ip->i_mapping = mapping;
1008 #ifdef STRUCT_ADDRESS_SPACE_HAS_GFP_MASK
1009 ip->i_data.gfp_mask = GFP_HIGHUSER;
1011 #if defined(AFS_LINUX26_ENV)
1012 mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
1014 extern struct backing_dev_info afs_backing_dev_info;
1016 mapping->backing_dev_info = &afs_backing_dev_info;
1021 #if !defined(AFS_LINUX26_ENV)
1023 ip->i_dev = afs_globalVFS->s_dev;
1025 ip->i_sb = afs_globalVFS;
1030 /* Hold it for the LRU (should make count 2) */
1031 VN_HOLD(AFSTOV(tvc));
1032 #else /* AFS_OSF_ENV */
1033 #if !defined(AFS_XBSD_ENV)
1034 VREFCOUNT_SET(tvc, 1); /* us */
1035 #endif /* AFS_XBSD_ENV */
1036 #endif /* AFS_OSF_ENV */
1037 #ifdef AFS_AIX32_ENV
1038 LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
1039 tvc->vmh = tvc->segid = NULL;
1042 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1043 #if defined(AFS_SUN5_ENV)
1044 rw_init(&tvc->rwlock, "vcache rwlock", RW_DEFAULT, NULL);
1046 #if defined(AFS_SUN55_ENV)
1047 /* This is required if the kaio (kernel aynchronous io)
1048 ** module is installed. Inside the kernel, the function
1049 ** check_vp( common/os/aio.c) checks to see if the kernel has
1050 ** to provide asynchronous io for this vnode. This
1051 ** function extracts the device number by following the
1052 ** v_data field of the vnode. If we do not set this field
1053 ** then the system panics. The value of the v_data field
1054 ** is not really important for AFS vnodes because the kernel
1055 ** does not do asynchronous io for regular files. Hence,
1056 ** for the time being, we fill up the v_data field with the
1057 ** vnode pointer itself. */
1058 tvc->v.v_data = (char *)tvc;
1059 #endif /* AFS_SUN55_ENV */
1061 afs_BozonInit(&tvc->pvnLock, tvc);
1065 tvc->callback = serverp; /* to minimize chance that clear
1066 * request is lost */
1067 /* initialize vnode data, note vrefCount is v.v_count */
1069 /* Don't forget to free the gnode space */
1070 tvc->v.v_gnode = gnodepnt =
1071 (struct gnode *)osi_AllocSmallSpace(sizeof(struct gnode));
1072 memset((char *)gnodepnt, 0, sizeof(struct gnode));
1074 #ifdef AFS_SGI64_ENV
1075 memset((void *)&(tvc->vc_bhv_desc), 0, sizeof(tvc->vc_bhv_desc));
1076 bhv_desc_init(&(tvc->vc_bhv_desc), tvc, tvc, &Afs_vnodeops);
1077 #ifdef AFS_SGI65_ENV
1078 vn_bhv_head_init(&(tvc->v.v_bh), "afsvp");
1079 vn_bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1081 bhv_head_init(&(tvc->v.v_bh));
1082 bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
1084 #ifdef AFS_SGI65_ENV
1085 tvc->v.v_mreg = tvc->v.v_mregb = (struct pregion *)tvc;
1086 #ifdef VNODE_TRACING
1087 tvc->v.v_trace = ktrace_alloc(VNODE_TRACE_SIZE, 0);
1089 init_bitlock(&tvc->v.v_pcacheflag, VNODE_PCACHE_LOCKBIT, "afs_pcache",
1091 init_mutex(&tvc->v.v_filocksem, MUTEX_DEFAULT, "afsvfl", (long)tvc);
1092 init_mutex(&tvc->v.v_buf_lock, MUTEX_DEFAULT, "afsvnbuf", (long)tvc);
1094 vnode_pcache_init(&tvc->v);
1095 #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
1096 /* Above define is never true execpt in SGI test kernels. */
1097 init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number);
1099 #ifdef INTR_KTHREADS
1100 AFS_VN_INIT_BUF_LOCK(&(tvc->v));
1103 SetAfsVnode(AFSTOV(tvc));
1104 #endif /* AFS_SGI64_ENV */
1105 #ifdef AFS_DARWIN_ENV
1106 tvc->v.v_ubcinfo = UBC_INFO_NULL;
1107 lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
1108 cache_purge(AFSTOV(tvc));
1109 tvc->v.v_data = tvc;
1110 tvc->v.v_tag = VT_AFS;
1111 /* VLISTNONE(&tvc->v); */
1112 tvc->v.v_freelist.tqe_next = 0;
1113 tvc->v.v_freelist.tqe_prev = (struct vnode **)0xdeadb;
1114 /*tvc->vrefCount++; */
1117 * The proper value for mvstat (for root fids) is setup by the caller.
1120 if (afid->Fid.Vnode == 1 && afid->Fid.Unique == 1)
1122 if (afs_globalVFS == 0)
1123 osi_Panic("afs globalvfs");
1124 vSetVfsp(tvc, afs_globalVFS);
1125 vSetType(tvc, VREG);
1127 tvc->v.v_vfsnext = afs_globalVFS->vfs_vnodes; /* link off vfs */
1128 tvc->v.v_vfsprev = NULL;
1129 afs_globalVFS->vfs_vnodes = &tvc->v;
1130 if (tvc->v.v_vfsnext != NULL)
1131 tvc->v.v_vfsnext->v_vfsprev = &tvc->v;
1132 tvc->v.v_next = gnodepnt->gn_vnode; /*Single vnode per gnode for us! */
1133 gnodepnt->gn_vnode = &tvc->v;
1136 tvc->v.g_dev = ((struct mount *)afs_globalVFS->vfs_data)->m_dev;
1138 #if defined(AFS_DUX40_ENV)
1139 insmntque(tvc, afs_globalVFS, &afs_ubcops);
1142 /* Is this needed??? */
1143 insmntque(tvc, afs_globalVFS);
1144 #endif /* AFS_OSF_ENV */
1145 #endif /* AFS_DUX40_ENV */
1146 #if defined(AFS_SGI_ENV)
1147 VN_SET_DPAGES(&(tvc->v), (struct pfdat *)NULL);
1148 osi_Assert((tvc->v.v_flag & VINACT) == 0);
1150 osi_Assert(VN_GET_PGCNT(&(tvc->v)) == 0);
1151 osi_Assert(tvc->mapcnt == 0 && tvc->vc_locktrips == 0);
1152 osi_Assert(tvc->vc_rwlockid == OSI_NO_LOCKID);
1153 osi_Assert(tvc->v.v_filocks == NULL);
1154 #if !defined(AFS_SGI65_ENV)
1155 osi_Assert(tvc->v.v_filocksem == NULL);
1157 osi_Assert(tvc->cred == NULL);
1158 #ifdef AFS_SGI64_ENV
1159 vnode_pcache_reinit(&tvc->v);
1160 tvc->v.v_rdev = NODEV;
1162 vn_initlist((struct vnlist *)&tvc->v);
1164 #endif /* AFS_SGI_ENV */
1166 osi_dnlc_purgedp(tvc); /* this may be overkill */
1167 memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
1168 memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
1172 tvc->hnext = afs_vhashT[i];
1173 afs_vhashT[i] = tvc;
1174 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1175 refpanic("NewVCache VLRU inconsistent");
1177 QAdd(&VLRU, &tvc->vlruq); /* put in lruq */
1178 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1179 refpanic("NewVCache VLRU inconsistent2");
1181 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
1182 refpanic("NewVCache VLRU inconsistent3");
1184 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
1185 refpanic("NewVCache VLRU inconsistent4");
1191 } /*afs_NewVCache */
1195 * afs_FlushActiveVcaches
1201 * doflocks : Do we handle flocks?
1203 /* LOCK: afs_FlushActiveVcaches afs_xvcache N */
1205 afs_FlushActiveVcaches(register afs_int32 doflocks)
1207 register struct vcache *tvc;
1209 register struct conn *tc;
1210 register afs_int32 code;
1211 register struct AFS_UCRED *cred = NULL;
1212 struct vrequest treq, ureq;
1213 struct AFSVolSync tsync;
1215 XSTATS_DECLS AFS_STATCNT(afs_FlushActiveVcaches);
1216 ObtainReadLock(&afs_xvcache);
1217 for (i = 0; i < VCSIZE; i++) {
1218 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1219 if (doflocks && tvc->flockCount != 0) {
1220 /* if this entry has an flock, send a keep-alive call out */
1222 ReleaseReadLock(&afs_xvcache);
1223 ObtainWriteLock(&tvc->lock, 51);
1225 afs_InitReq(&treq, afs_osi_credp);
1226 treq.flags |= O_NONBLOCK;
1228 tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
1230 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
1233 RXAFS_ExtendLock(tc->id,
1234 (struct AFSFid *)&tvc->fid.Fid,
1240 } while (afs_Analyze
1241 (tc, code, &tvc->fid, &treq,
1242 AFS_STATS_FS_RPCIDX_EXTENDLOCK, SHARED_LOCK, NULL));
1244 ReleaseWriteLock(&tvc->lock);
1245 ObtainReadLock(&afs_xvcache);
1249 if ((tvc->states & CCore) || (tvc->states & CUnlinkedDel)) {
1251 * Don't let it evaporate in case someone else is in
1252 * this code. Also, drop the afs_xvcache lock while
1253 * getting vcache locks.
1256 ReleaseReadLock(&afs_xvcache);
1257 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1258 afs_BozonLock(&tvc->pvnLock, tvc);
1260 #if defined(AFS_SGI_ENV)
1262 * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
1264 osi_Assert(VREFCOUNT(tvc) > 0);
1265 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1267 ObtainWriteLock(&tvc->lock, 52);
1268 if (tvc->states & CCore) {
1269 tvc->states &= ~CCore;
1270 /* XXXX Find better place-holder for cred XXXX */
1271 cred = (struct AFS_UCRED *)tvc->linkData;
1272 tvc->linkData = NULL; /* XXX */
1273 afs_InitReq(&ureq, cred);
1274 afs_Trace2(afs_iclSetp, CM_TRACE_ACTCCORE,
1275 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32,
1276 tvc->execsOrWriters);
1277 code = afs_StoreOnLastReference(tvc, &ureq);
1278 ReleaseWriteLock(&tvc->lock);
1279 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1280 afs_BozonUnlock(&tvc->pvnLock, tvc);
1282 hzero(tvc->flushDV);
1285 if (code && code != VNOVNODE) {
1286 afs_StoreWarn(code, tvc->fid.Fid.Volume,
1287 /* /dev/console */ 1);
1289 } else if (tvc->states & CUnlinkedDel) {
1293 ReleaseWriteLock(&tvc->lock);
1294 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1295 afs_BozonUnlock(&tvc->pvnLock, tvc);
1297 #if defined(AFS_SGI_ENV)
1298 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1300 afs_remunlink(tvc, 0);
1301 #if defined(AFS_SGI_ENV)
1302 AFS_RWLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1305 /* lost (or won, perhaps) the race condition */
1306 ReleaseWriteLock(&tvc->lock);
1307 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1308 afs_BozonUnlock(&tvc->pvnLock, tvc);
1311 #if defined(AFS_SGI_ENV)
1312 AFS_RWUNLOCK((vnode_t *) tvc, VRWLOCK_WRITE);
1314 ObtainReadLock(&afs_xvcache);
1320 AFS_RELE(AFSTOV(tvc));
1322 /* Matches write code setting CCore flag */
1326 #ifdef AFS_DARWIN_ENV
1327 if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
1329 panic("flushactive open, hasubc, but refcnt 1");
1330 osi_VM_TryReclaim(tvc, 0);
1335 ReleaseReadLock(&afs_xvcache);
1343 * Make sure a cache entry is up-to-date status-wise.
1345 * NOTE: everywhere that calls this can potentially be sped up
1346 * by checking CStatd first, and avoiding doing the InitReq
1347 * if this is up-to-date.
1349 * Anymore, the only places that call this KNOW already that the
1350 * vcache is not up-to-date, so we don't screw around.
1353 * avc : Ptr to vcache entry to verify.
1358 afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq)
1360 register struct vcache *tvc;
1362 AFS_STATCNT(afs_VerifyVCache);
1364 #if defined(AFS_OSF_ENV)
1365 ObtainReadLock(&avc->lock);
1366 if (afs_IsWired(avc)) {
1367 ReleaseReadLock(&avc->lock);
1370 ReleaseReadLock(&avc->lock);
1371 #endif /* AFS_OSF_ENV */
1372 /* otherwise we must fetch the status info */
1374 ObtainWriteLock(&avc->lock, 53);
1375 if (avc->states & CStatd) {
1376 ReleaseWriteLock(&avc->lock);
1379 ObtainWriteLock(&afs_xcbhash, 461);
1380 avc->states &= ~(CStatd | CUnique);
1381 avc->callback = NULL;
1382 afs_DequeueCallback(avc);
1383 ReleaseWriteLock(&afs_xcbhash);
1384 ReleaseWriteLock(&avc->lock);
1386 /* since we've been called back, or the callback has expired,
1387 * it's possible that the contents of this directory, or this
1388 * file's name have changed, thus invalidating the dnlc contents.
1390 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1391 osi_dnlc_purgedp(avc);
1393 osi_dnlc_purgevp(avc);
1395 /* fetch the status info */
1396 tvc = afs_GetVCache(&avc->fid, areq, NULL, avc);
1399 /* Put it back; caller has already incremented vrefCount */
1403 } /*afs_VerifyVCache */
1410 * Simple copy of stat info into cache.
1413 * avc : Ptr to vcache entry involved.
1414 * astat : Ptr to stat info to copy.
1417 * Nothing interesting.
1419 * Callers: as of 1992-04-29, only called by WriteVCache
1422 afs_SimpleVStat(register struct vcache *avc,
1423 register struct AFSFetchStatus *astat, struct vrequest *areq)
1426 AFS_STATCNT(afs_SimpleVStat);
1429 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1430 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1432 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1434 #ifdef AFS_64BIT_CLIENT
1435 FillInt64(length, astat->Length_hi, astat->Length);
1436 #else /* AFS_64BIT_CLIENT */
1437 length = astat->Length;
1438 #endif /* AFS_64BIT_CLIENT */
1439 #if defined(AFS_SGI_ENV)
1440 osi_Assert((valusema(&avc->vc_rwlock) <= 0)
1441 && (OSI_GET_LOCKID() == avc->vc_rwlockid));
1442 if (length < avc->m.Length) {
1443 vnode_t *vp = (vnode_t *) avc;
1445 osi_Assert(WriteLocked(&avc->lock));
1446 ReleaseWriteLock(&avc->lock);
1448 PTOSSVP(vp, (off_t) length, (off_t) MAXLONG);
1450 ObtainWriteLock(&avc->lock, 67);
1453 /* if writing the file, don't fetch over this value */
1454 afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT, ICL_TYPE_POINTER, avc,
1455 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1456 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1457 avc->m.Length = length;
1458 avc->m.Date = astat->ClientModTime;
1460 avc->m.Owner = astat->Owner;
1461 avc->m.Group = astat->Group;
1462 avc->m.Mode = astat->UnixModeBits;
1463 if (vType(avc) == VREG) {
1464 avc->m.Mode |= S_IFREG;
1465 } else if (vType(avc) == VDIR) {
1466 avc->m.Mode |= S_IFDIR;
1467 } else if (vType(avc) == VLNK) {
1468 avc->m.Mode |= S_IFLNK;
1469 if ((avc->m.Mode & 0111) == 0)
1472 if (avc->states & CForeign) {
1473 struct axscache *ac;
1474 avc->anyAccess = astat->AnonymousAccess;
1476 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1478 * Caller has at least one bit not covered by anonymous, and
1479 * thus may have interesting rights.
1481 * HOWEVER, this is a really bad idea, because any access query
1482 * for bits which aren't covered by anonymous, on behalf of a user
1483 * who doesn't have any special rights, will result in an answer of
1484 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1485 * It's an especially bad idea under Ultrix, since (due to the lack of
1486 * a proper access() call) it must perform several afs_access() calls
1487 * in order to create magic mode bits that vary according to who makes
1488 * the call. In other words, _every_ stat() generates a test for
1491 #endif /* badidea */
1492 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1493 ac->axess = astat->CallerAccess;
1494 else /* not found, add a new one if possible */
1495 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1499 } /*afs_SimpleVStat */
1506 * Store the status info *only* back to the server for a
1510 * avc : Ptr to the vcache entry.
1511 * astatus : Ptr to the status info to store.
1512 * areq : Ptr to the associated vrequest.
1515 * Must be called with a shared lock held on the vnode.
1519 afs_WriteVCache(register struct vcache *avc,
1520 register struct AFSStoreStatus *astatus,
1521 struct vrequest *areq)
1525 struct AFSFetchStatus OutStatus;
1526 struct AFSVolSync tsync;
1527 XSTATS_DECLS AFS_STATCNT(afs_WriteVCache);
1528 afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
1529 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
1532 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1534 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
1537 RXAFS_StoreStatus(tc->id, (struct AFSFid *)&avc->fid.Fid,
1538 astatus, &OutStatus, &tsync);
1543 } while (afs_Analyze
1544 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STORESTATUS,
1545 SHARED_LOCK, NULL));
1547 UpgradeSToWLock(&avc->lock, 20);
1549 /* success, do the changes locally */
1550 afs_SimpleVStat(avc, &OutStatus, areq);
1552 * Update the date, too. SimpleVStat didn't do this, since
1553 * it thought we were doing this after fetching new status
1554 * over a file being written.
1556 avc->m.Date = OutStatus.ClientModTime;
1558 /* failure, set up to check with server next time */
1559 ObtainWriteLock(&afs_xcbhash, 462);
1560 afs_DequeueCallback(avc);
1561 avc->states &= ~(CStatd | CUnique); /* turn off stat valid flag */
1562 ReleaseWriteLock(&afs_xcbhash);
1563 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
1564 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
1566 ConvertWToSLock(&avc->lock);
1569 } /*afs_WriteVCache */
1575 * Copy astat block into vcache info
1578 * avc : Ptr to vcache entry.
1579 * astat : Ptr to stat block to copy in.
1580 * areq : Ptr to associated request.
1583 * Must be called under a write lock
1585 * Note: this code may get dataversion and length out of sync if the file has
1586 * been modified. This is less than ideal. I haven't thought about
1587 * it sufficiently to be certain that it is adequate.
1590 afs_ProcessFS(register struct vcache *avc,
1591 register struct AFSFetchStatus *astat, struct vrequest *areq)
1594 AFS_STATCNT(afs_ProcessFS);
1596 #ifdef AFS_64BIT_CLIENT
1597 FillInt64(length, astat->Length_hi, astat->Length);
1598 #else /* AFS_64BIT_CLIENT */
1599 length = astat->Length;
1600 #endif /* AFS_64BIT_CLIENT */
1601 /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
1602 * number for each bulk status request. Under no circumstances
1603 * should afs_DoBulkStat store a sequence number if the new
1604 * length will be ignored when afs_ProcessFS is called with
1605 * new stats. If you change the following conditional then you
1606 * also need to change the conditional in afs_DoBulkStat. */
1608 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1609 && !AFS_VN_MAPPED((vnode_t *) avc)) {
1611 if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)) {
1613 /* if we're writing or mapping this file, don't fetch over these
1616 afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
1617 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1618 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1619 avc->m.Length = length;
1620 avc->m.Date = astat->ClientModTime;
1622 hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
1623 avc->m.Owner = astat->Owner;
1624 avc->m.Mode = astat->UnixModeBits;
1625 avc->m.Group = astat->Group;
1626 avc->m.LinkCount = astat->LinkCount;
1627 if (astat->FileType == File) {
1628 vSetType(avc, VREG);
1629 avc->m.Mode |= S_IFREG;
1630 } else if (astat->FileType == Directory) {
1631 vSetType(avc, VDIR);
1632 avc->m.Mode |= S_IFDIR;
1633 } else if (astat->FileType == SymbolicLink) {
1634 if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
1635 vSetType(avc, VDIR);
1636 avc->m.Mode |= S_IFDIR;
1638 vSetType(avc, VLNK);
1639 avc->m.Mode |= S_IFLNK;
1641 if ((avc->m.Mode & 0111) == 0) {
1645 avc->anyAccess = astat->AnonymousAccess;
1647 if ((astat->CallerAccess & ~astat->AnonymousAccess))
1649 * Caller has at least one bit not covered by anonymous, and
1650 * thus may have interesting rights.
1652 * HOWEVER, this is a really bad idea, because any access query
1653 * for bits which aren't covered by anonymous, on behalf of a user
1654 * who doesn't have any special rights, will result in an answer of
1655 * the form "I don't know, lets make a FetchStatus RPC and find out!"
1656 * It's an especially bad idea under Ultrix, since (due to the lack of
1657 * a proper access() call) it must perform several afs_access() calls
1658 * in order to create magic mode bits that vary according to who makes
1659 * the call. In other words, _every_ stat() generates a test for
1662 #endif /* badidea */
1664 struct axscache *ac;
1665 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1666 ac->axess = astat->CallerAccess;
1667 else /* not found, add a new one if possible */
1668 afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1670 #ifdef AFS_LINUX22_ENV
1671 vcache2inode(avc); /* Set the inode attr cache */
1673 #ifdef AFS_DARWIN_ENV
1674 osi_VM_Setup(avc, 1);
1677 } /*afs_ProcessFS */
1681 afs_RemoteLookup(register struct VenusFid *afid, struct vrequest *areq,
1682 char *name, struct VenusFid *nfid,
1683 struct AFSFetchStatus *OutStatusp,
1684 struct AFSCallBack *CallBackp, struct server **serverp,
1685 struct AFSVolSync *tsyncp)
1689 register struct conn *tc;
1690 struct AFSFetchStatus OutDirStatus;
1691 XSTATS_DECLS if (!name)
1692 name = ""; /* XXX */
1694 tc = afs_Conn(afid, areq, SHARED_LOCK);
1697 *serverp = tc->srvr->server;
1699 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
1702 RXAFS_Lookup(tc->id, (struct AFSFid *)&afid->Fid, name,
1703 (struct AFSFid *)&nfid->Fid, OutStatusp,
1704 &OutDirStatus, CallBackp, tsyncp);
1709 } while (afs_Analyze
1710 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_XLOOKUP, SHARED_LOCK,
1721 * Given a file id and a vrequest structure, fetch the status
1722 * information associated with the file.
1726 * areq : Ptr to associated vrequest structure, specifying the
1727 * user whose authentication tokens will be used.
1728 * avc : caller may already have a vcache for this file, which is
1732 * The cache entry is returned with an increased vrefCount field.
1733 * The entry must be discarded by calling afs_PutVCache when you
1734 * are through using the pointer to the cache entry.
1736 * You should not hold any locks when calling this function, except
1737 * locks on other vcache entries. If you lock more than one vcache
1738 * entry simultaneously, you should lock them in this order:
1740 * 1. Lock all files first, then directories.
1741 * 2. Within a particular type, lock entries in Fid.Vnode order.
1743 * This locking hierarchy is convenient because it allows locking
1744 * of a parent dir cache entry, given a file (to check its access
1745 * control list). It also allows renames to be handled easily by
1746 * locking directories in a constant order.
1747 * NB. NewVCache -> FlushVCache presently (4/10/95) drops the xvcache lock.
1749 /* might have a vcache structure already, which must
1750 * already be held by the caller */
1753 afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq,
1754 afs_int32 * cached, struct vcache *avc)
1757 afs_int32 code, newvcache = 0;
1758 register struct vcache *tvc;
1762 AFS_STATCNT(afs_GetVCache);
1765 *cached = 0; /* Init just in case */
1767 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1771 ObtainSharedLock(&afs_xvcache, 5);
1773 tvc = afs_FindVCache(afid, &retry, DO_STATS | DO_VLRU);
1775 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1776 ReleaseSharedLock(&afs_xvcache);
1777 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1785 if (tvc->states & CStatd) {
1786 ReleaseSharedLock(&afs_xvcache);
1790 UpgradeSToWLock(&afs_xvcache, 21);
1792 /* no cache entry, better grab one */
1793 tvc = afs_NewVCache(afid, NULL);
1796 ConvertWToSLock(&afs_xvcache);
1797 afs_stats_cmperf.vcacheMisses++;
1800 ReleaseSharedLock(&afs_xvcache);
1802 ObtainWriteLock(&tvc->lock, 54);
1804 if (tvc->states & CStatd) {
1805 #ifdef AFS_LINUX22_ENV
1808 ReleaseWriteLock(&tvc->lock);
1809 #ifdef AFS_DARWIN_ENV
1810 osi_VM_Setup(tvc, 0);
1814 #if defined(AFS_OSF_ENV)
1815 if (afs_IsWired(tvc)) {
1816 ReleaseWriteLock(&tvc->lock);
1819 #endif /* AFS_OSF_ENV */
1821 VOP_LOCK(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY, curproc);
1822 uvm_vnp_uncache(AFSTOV(tvc));
1823 VOP_UNLOCK(AFSTOV(tvc), 0, curproc);
1827 * XXX - I really don't like this. Should try to understand better.
1828 * It seems that sometimes, when we get called, we already hold the
1829 * lock on the vnode (e.g., from afs_getattr via afs_VerifyVCache).
1830 * We can't drop the vnode lock, because that could result in a race.
1831 * Sometimes, though, we get here and don't hold the vnode lock.
1832 * I hate code paths that sometimes hold locks and sometimes don't.
1833 * In any event, the dodge we use here is to check whether the vnode
1834 * is locked, and if it isn't, then we gain and drop it around the call
1835 * to vinvalbuf; otherwise, we leave it alone.
1842 #ifdef AFS_FBSD50_ENV
1843 iheldthelock = VOP_ISLOCKED(vp, curthread);
1845 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
1846 vinvalbuf(vp, V_SAVE, osi_curcred(), curthread, PINOD, 0);
1848 VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
1850 iheldthelock = VOP_ISLOCKED(vp, curproc);
1852 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
1853 vinvalbuf(vp, V_SAVE, osi_curcred(), curproc, PINOD, 0);
1855 VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
1860 ObtainWriteLock(&afs_xcbhash, 464);
1861 tvc->states &= ~CUnique;
1863 afs_DequeueCallback(tvc);
1864 ReleaseWriteLock(&afs_xcbhash);
1866 /* It is always appropriate to throw away all the access rights? */
1867 afs_FreeAllAxs(&(tvc->Access));
1868 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-volume info */
1870 if ((tvp->states & VForeign)) {
1872 tvc->states |= CForeign;
1873 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
1874 && (tvp->rootUnique == afid->Fid.Unique)) {
1878 if (tvp->states & VRO)
1880 if (tvp->states & VBackup)
1881 tvc->states |= CBackup;
1882 /* now copy ".." entry back out of volume structure, if necessary */
1883 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
1885 tvc->mvid = (struct VenusFid *)
1886 osi_AllocSmallSpace(sizeof(struct VenusFid));
1887 *tvc->mvid = tvp->dotdot;
1889 afs_PutVolume(tvp, READ_LOCK);
1893 afs_RemoveVCB(afid);
1895 struct AFSFetchStatus OutStatus;
1897 if (afs_DynrootNewVnode(tvc, &OutStatus)) {
1898 afs_ProcessFS(tvc, &OutStatus, areq);
1899 tvc->states |= CStatd | CUnique;
1902 code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
1907 ReleaseWriteLock(&tvc->lock);
1909 ObtainReadLock(&afs_xvcache);
1911 ReleaseReadLock(&afs_xvcache);
1915 ReleaseWriteLock(&tvc->lock);
1918 } /*afs_GetVCache */
1923 afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
1924 afs_int32 * cached, struct vcache *adp, char *aname)
1926 afs_int32 code, now, newvcache = 0;
1927 struct VenusFid nfid;
1928 register struct vcache *tvc;
1930 struct AFSFetchStatus OutStatus;
1931 struct AFSCallBack CallBack;
1932 struct AFSVolSync tsync;
1933 struct server *serverp = 0;
1937 AFS_STATCNT(afs_GetVCache);
1939 *cached = 0; /* Init just in case */
1941 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1945 ObtainReadLock(&afs_xvcache);
1946 tvc = afs_FindVCache(afid, &retry, DO_STATS /* no vlru */ );
1949 ReleaseReadLock(&afs_xvcache);
1951 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1952 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1956 ObtainReadLock(&tvc->lock);
1958 if (tvc->states & CStatd) {
1962 ReleaseReadLock(&tvc->lock);
1965 tvc->states &= ~CUnique;
1967 ReleaseReadLock(&tvc->lock);
1968 ObtainReadLock(&afs_xvcache);
1972 ReleaseReadLock(&afs_xvcache);
1974 /* lookup the file */
1977 origCBs = afs_allCBs; /* if anything changes, we don't have a cb */
1979 afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
1982 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1986 ObtainSharedLock(&afs_xvcache, 6);
1987 tvc = afs_FindVCache(&nfid, &retry, DO_VLRU /* no xstats now */ );
1989 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1990 ReleaseSharedLock(&afs_xvcache);
1991 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1997 /* no cache entry, better grab one */
1998 UpgradeSToWLock(&afs_xvcache, 22);
1999 tvc = afs_NewVCache(&nfid, serverp);
2001 ConvertWToSLock(&afs_xvcache);
2004 ReleaseSharedLock(&afs_xvcache);
2005 ObtainWriteLock(&tvc->lock, 55);
2007 /* It is always appropriate to throw away all the access rights? */
2008 afs_FreeAllAxs(&(tvc->Access));
2009 tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-vol info */
2011 if ((tvp->states & VForeign)) {
2013 tvc->states |= CForeign;
2014 if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
2015 && (tvp->rootUnique == afid->Fid.Unique))
2018 if (tvp->states & VRO)
2020 if (tvp->states & VBackup)
2021 tvc->states |= CBackup;
2022 /* now copy ".." entry back out of volume structure, if necessary */
2023 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2025 tvc->mvid = (struct VenusFid *)
2026 osi_AllocSmallSpace(sizeof(struct VenusFid));
2027 *tvc->mvid = tvp->dotdot;
2032 ObtainWriteLock(&afs_xcbhash, 465);
2033 afs_DequeueCallback(tvc);
2034 tvc->states &= ~(CStatd | CUnique);
2035 ReleaseWriteLock(&afs_xcbhash);
2036 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2037 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2039 afs_PutVolume(tvp, READ_LOCK);
2040 ReleaseWriteLock(&tvc->lock);
2041 ObtainReadLock(&afs_xvcache);
2043 ReleaseReadLock(&afs_xvcache);
2047 ObtainWriteLock(&afs_xcbhash, 466);
2048 if (origCBs == afs_allCBs) {
2049 if (CallBack.ExpirationTime) {
2050 tvc->callback = serverp;
2051 tvc->cbExpires = CallBack.ExpirationTime + now;
2052 tvc->states |= CStatd | CUnique;
2053 tvc->states &= ~CBulkFetching;
2054 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvp);
2055 } else if (tvc->states & CRO) {
2056 /* adapt gives us an hour. */
2057 tvc->cbExpires = 3600 + osi_Time();
2058 /*XXX*/ tvc->states |= CStatd | CUnique;
2059 tvc->states &= ~CBulkFetching;
2060 afs_QueueCallback(tvc, CBHash(3600), tvp);
2062 tvc->callback = NULL;
2063 afs_DequeueCallback(tvc);
2064 tvc->states &= ~(CStatd | CUnique);
2065 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2066 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2069 afs_DequeueCallback(tvc);
2070 tvc->states &= ~CStatd;
2071 tvc->states &= ~CUnique;
2072 tvc->callback = NULL;
2073 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2074 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2076 ReleaseWriteLock(&afs_xcbhash);
2078 afs_PutVolume(tvp, READ_LOCK);
2079 afs_ProcessFS(tvc, &OutStatus, areq);
2081 ReleaseWriteLock(&tvc->lock);
2087 afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq,
2088 afs_int32 * cached, struct volume *tvolp)
2090 afs_int32 code = 0, i, newvcache = 0, haveStatus = 0;
2091 afs_int32 getNewFid = 0;
2093 struct VenusFid nfid;
2094 register struct vcache *tvc;
2095 struct server *serverp = 0;
2096 struct AFSFetchStatus OutStatus;
2097 struct AFSCallBack CallBack;
2098 struct AFSVolSync tsync;
2104 if (!tvolp->rootVnode || getNewFid) {
2105 struct VenusFid tfid;
2108 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2109 origCBs = afs_allCBs; /* ignore InitCallBackState */
2111 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2116 /* ReleaseReadLock(&tvolp->lock); */
2117 ObtainWriteLock(&tvolp->lock, 56);
2118 tvolp->rootVnode = afid->Fid.Vnode = nfid.Fid.Vnode;
2119 tvolp->rootUnique = afid->Fid.Unique = nfid.Fid.Unique;
2120 ReleaseWriteLock(&tvolp->lock);
2121 /* ObtainReadLock(&tvolp->lock);*/
2124 afid->Fid.Vnode = tvolp->rootVnode;
2125 afid->Fid.Unique = tvolp->rootUnique;
2128 ObtainSharedLock(&afs_xvcache, 7);
2130 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2131 if (!FidCmp(&(tvc->fid), afid)) {
2133 /* Grab this vnode, possibly reactivating from the free list */
2134 /* for the present (95.05.25) everything on the hash table is
2135 * definitively NOT in the free list -- at least until afs_reclaim
2136 * can be safely implemented */
2139 vg = vget(AFSTOV(tvc)); /* this bumps ref count */
2143 #endif /* AFS_OSF_ENV */
2148 if (!haveStatus && (!tvc || !(tvc->states & CStatd))) {
2149 /* Mount point no longer stat'd or unknown. FID may have changed. */
2152 AFS_RELE(AFSTOV(tvc));
2156 ReleaseSharedLock(&afs_xvcache);
2161 UpgradeSToWLock(&afs_xvcache, 23);
2162 /* no cache entry, better grab one */
2163 tvc = afs_NewVCache(afid, NULL);
2165 afs_stats_cmperf.vcacheMisses++;
2169 afs_stats_cmperf.vcacheHits++;
2171 /* we already bumped the ref count in the for loop above */
2172 #else /* AFS_OSF_ENV */
2175 UpgradeSToWLock(&afs_xvcache, 24);
2176 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2177 refpanic("GRVC VLRU inconsistent0");
2179 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2180 refpanic("GRVC VLRU inconsistent1");
2182 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2183 refpanic("GRVC VLRU inconsistent2");
2185 QRemove(&tvc->vlruq); /* move to lruq head */
2186 QAdd(&VLRU, &tvc->vlruq);
2187 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2188 refpanic("GRVC VLRU inconsistent3");
2190 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2191 refpanic("GRVC VLRU inconsistent4");
2193 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2194 refpanic("GRVC VLRU inconsistent5");
2199 ReleaseWriteLock(&afs_xvcache);
2201 if (tvc->states & CStatd) {
2205 ObtainReadLock(&tvc->lock);
2206 tvc->states &= ~CUnique;
2207 tvc->callback = NULL; /* redundant, perhaps */
2208 ReleaseReadLock(&tvc->lock);
2211 ObtainWriteLock(&tvc->lock, 57);
2213 /* It is always appropriate to throw away all the access rights? */
2214 afs_FreeAllAxs(&(tvc->Access));
2217 tvc->states |= CForeign;
2218 if (tvolp->states & VRO)
2220 if (tvolp->states & VBackup)
2221 tvc->states |= CBackup;
2222 /* now copy ".." entry back out of volume structure, if necessary */
2223 if (newvcache && (tvolp->rootVnode == afid->Fid.Vnode)
2224 && (tvolp->rootUnique == afid->Fid.Unique)) {
2227 if (tvc->mvstat == 2 && tvolp->dotdot.Fid.Volume != 0) {
2229 tvc->mvid = (struct VenusFid *)
2230 osi_AllocSmallSpace(sizeof(struct VenusFid));
2231 *tvc->mvid = tvolp->dotdot;
2235 afs_RemoveVCB(afid);
2238 struct VenusFid tfid;
2241 tfid.Fid.Vnode = 0; /* Means get rootfid of volume */
2242 origCBs = afs_allCBs; /* ignore InitCallBackState */
2244 afs_RemoteLookup(&tfid, areq, NULL, &nfid, &OutStatus, &CallBack,
2249 ObtainWriteLock(&afs_xcbhash, 467);
2250 afs_DequeueCallback(tvc);
2251 tvc->callback = NULL;
2252 tvc->states &= ~(CStatd | CUnique);
2253 ReleaseWriteLock(&afs_xcbhash);
2254 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2255 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2256 ReleaseWriteLock(&tvc->lock);
2257 ObtainReadLock(&afs_xvcache);
2259 ReleaseReadLock(&afs_xvcache);
2263 ObtainWriteLock(&afs_xcbhash, 468);
2264 if (origCBs == afs_allCBs) {
2265 tvc->states |= CTruth;
2266 tvc->callback = serverp;
2267 if (CallBack.ExpirationTime != 0) {
2268 tvc->cbExpires = CallBack.ExpirationTime + start;
2269 tvc->states |= CStatd;
2270 tvc->states &= ~CBulkFetching;
2271 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvolp);
2272 } else if (tvc->states & CRO) {
2273 /* adapt gives us an hour. */
2274 tvc->cbExpires = 3600 + osi_Time();
2275 /*XXX*/ tvc->states |= CStatd;
2276 tvc->states &= ~CBulkFetching;
2277 afs_QueueCallback(tvc, CBHash(3600), tvolp);
2280 afs_DequeueCallback(tvc);
2281 tvc->callback = NULL;
2282 tvc->states &= ~(CStatd | CUnique);
2283 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2284 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2286 ReleaseWriteLock(&afs_xcbhash);
2287 afs_ProcessFS(tvc, &OutStatus, areq);
2289 ReleaseWriteLock(&tvc->lock);
2296 * must be called with avc write-locked
2297 * don't absolutely have to invalidate the hint unless the dv has
2298 * changed, but be sure to get it right else there will be consistency bugs.
2301 afs_FetchStatus(struct vcache * avc, struct VenusFid * afid,
2302 struct vrequest * areq, struct AFSFetchStatus * Outsp)
2305 afs_uint32 start = 0;
2306 register struct conn *tc;
2307 struct AFSCallBack CallBack;
2308 struct AFSVolSync tsync;
2309 struct volume *volp;
2312 tc = afs_Conn(afid, areq, SHARED_LOCK);
2313 avc->quick.stamp = 0;
2314 avc->h1.dchint = NULL; /* invalidate hints */
2316 avc->callback = tc->srvr->server;
2318 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
2321 RXAFS_FetchStatus(tc->id, (struct AFSFid *)&afid->Fid, Outsp,
2329 } while (afs_Analyze
2330 (tc, code, afid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS,
2331 SHARED_LOCK, NULL));
2334 afs_ProcessFS(avc, Outsp, areq);
2335 volp = afs_GetVolume(afid, areq, READ_LOCK);
2336 ObtainWriteLock(&afs_xcbhash, 469);
2337 avc->states |= CTruth;
2338 if (avc->callback /* check for race */ ) {
2339 if (CallBack.ExpirationTime != 0) {
2340 avc->cbExpires = CallBack.ExpirationTime + start;
2341 avc->states |= CStatd;
2342 avc->states &= ~CBulkFetching;
2343 afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
2344 } else if (avc->states & CRO) { /* ordinary callback on a read-only volume -- AFS 3.2 style */
2345 avc->cbExpires = 3600 + start;
2346 avc->states |= CStatd;
2347 avc->states &= ~CBulkFetching;
2348 afs_QueueCallback(avc, CBHash(3600), volp);
2350 afs_DequeueCallback(avc);
2351 avc->callback = NULL;
2352 avc->states &= ~(CStatd | CUnique);
2353 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2354 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2357 afs_DequeueCallback(avc);
2358 avc->callback = NULL;
2359 avc->states &= ~(CStatd | CUnique);
2360 if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
2361 osi_dnlc_purgedp(avc); /* if it (could be) a directory */
2363 ReleaseWriteLock(&afs_xcbhash);
2365 afs_PutVolume(volp, READ_LOCK);
2367 /* used to undo the local callback, but that's too extreme.
2368 * There are plenty of good reasons that fetchstatus might return
2369 * an error, such as EPERM. If we have the vnode cached, statd,
2370 * with callback, might as well keep track of the fact that we
2371 * don't have access...
2373 if (code == EPERM || code == EACCES) {
2374 struct axscache *ac;
2375 if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
2377 else /* not found, add a new one if possible */
2378 afs_AddAxs(avc->Access, areq->uid, 0);
2389 * Stuff some information into the vcache for the given file.
2392 * afid : File in question.
2393 * OutStatus : Fetch status on the file.
2394 * CallBack : Callback info.
2395 * tc : RPC connection involved.
2396 * areq : vrequest involved.
2399 * Nothing interesting.
2402 afs_StuffVcache(register struct VenusFid *afid,
2403 struct AFSFetchStatus *OutStatus,
2404 struct AFSCallBack *CallBack, register struct conn *tc,
2405 struct vrequest *areq)
2407 register afs_int32 code, i, newvcache = 0;
2408 register struct vcache *tvc;
2409 struct AFSVolSync tsync;
2411 struct axscache *ac;
2414 AFS_STATCNT(afs_StuffVcache);
2415 #ifdef IFS_VCACHECOUNT
2420 ObtainSharedLock(&afs_xvcache, 8);
2422 tvc = afs_FindVCache(afid, &retry, DO_VLRU /* no stats */ );
2424 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2425 ReleaseSharedLock(&afs_xvcache);
2426 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2432 /* no cache entry, better grab one */
2433 UpgradeSToWLock(&afs_xvcache, 25);
2434 tvc = afs_NewVCache(afid, NULL);
2436 ConvertWToSLock(&afs_xvcache);
2439 ReleaseSharedLock(&afs_xvcache);
2440 ObtainWriteLock(&tvc->lock, 58);
2442 tvc->states &= ~CStatd;
2443 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2444 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2446 /* Is it always appropriate to throw away all the access rights? */
2447 afs_FreeAllAxs(&(tvc->Access));
2449 /*Copy useful per-volume info */
2450 tvp = afs_GetVolume(afid, areq, READ_LOCK);
2452 if (newvcache && (tvp->states & VForeign))
2453 tvc->states |= CForeign;
2454 if (tvp->states & VRO)
2456 if (tvp->states & VBackup)
2457 tvc->states |= CBackup;
2459 * Now, copy ".." entry back out of volume structure, if
2462 if (tvc->mvstat == 2 && tvp->dotdot.Fid.Volume != 0) {
2464 tvc->mvid = (struct VenusFid *)
2465 osi_AllocSmallSpace(sizeof(struct VenusFid));
2466 *tvc->mvid = tvp->dotdot;
2469 /* store the stat on the file */
2470 afs_RemoveVCB(afid);
2471 afs_ProcessFS(tvc, OutStatus, areq);
2472 tvc->callback = tc->srvr->server;
2474 /* we use osi_Time twice below. Ideally, we would use the time at which
2475 * the FetchStatus call began, instead, but we don't have it here. So we
2476 * make do with "now". In the CRO case, it doesn't really matter. In
2477 * the other case, we hope that the difference between "now" and when the
2478 * call actually began execution on the server won't be larger than the
2479 * padding which the server keeps. Subtract 1 second anyway, to be on
2480 * the safe side. Can't subtract more because we don't know how big
2481 * ExpirationTime is. Possible consistency problems may arise if the call
2482 * timeout period becomes longer than the server's expiration padding. */
2483 ObtainWriteLock(&afs_xcbhash, 470);
2484 if (CallBack->ExpirationTime != 0) {
2485 tvc->cbExpires = CallBack->ExpirationTime + osi_Time() - 1;
2486 tvc->states |= CStatd;
2487 tvc->states &= ~CBulkFetching;
2488 afs_QueueCallback(tvc, CBHash(CallBack->ExpirationTime), tvp);
2489 } else if (tvc->states & CRO) {
2490 /* old-fashioned AFS 3.2 style */
2491 tvc->cbExpires = 3600 + osi_Time();
2492 /*XXX*/ tvc->states |= CStatd;
2493 tvc->states &= ~CBulkFetching;
2494 afs_QueueCallback(tvc, CBHash(3600), tvp);
2496 afs_DequeueCallback(tvc);
2497 tvc->callback = NULL;
2498 tvc->states &= ~(CStatd | CUnique);
2499 if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1))
2500 osi_dnlc_purgedp(tvc); /* if it (could be) a directory */
2502 ReleaseWriteLock(&afs_xcbhash);
2504 afs_PutVolume(tvp, READ_LOCK);
2506 /* look in per-pag cache */
2507 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, areq->uid)))
2508 ac->axess = OutStatus->CallerAccess; /* substitute pags */
2509 else /* not found, add a new one if possible */
2510 afs_AddAxs(tvc->Access, areq->uid, OutStatus->CallerAccess);
2512 ReleaseWriteLock(&tvc->lock);
2513 afs_Trace4(afs_iclSetp, CM_TRACE_STUFFVCACHE, ICL_TYPE_POINTER, tvc,
2514 ICL_TYPE_POINTER, tvc->callback, ICL_TYPE_INT32,
2515 tvc->cbExpires, ICL_TYPE_INT32, tvc->cbExpires - osi_Time());
2517 * Release ref count... hope this guy stays around...
2520 } /*afs_StuffVcache */
2527 * Decrements the reference count on a cache entry.
2530 * avc : Pointer to the cache entry to decrement.
2533 * Nothing interesting.
2536 afs_PutVCache(register struct vcache *avc)
2538 AFS_STATCNT(afs_PutVCache);
2540 * Can we use a read lock here?
2542 ObtainReadLock(&afs_xvcache);
2544 ReleaseReadLock(&afs_xvcache);
2545 } /*afs_PutVCache */
2551 * Find a vcache entry given a fid.
2554 * afid : Pointer to the fid whose cache entry we desire.
2555 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2556 * unlock the vnode, and try again.
2557 * flags: bit 1 to specify whether to compute hit statistics. Not
2558 * set if FindVCache is called as part of internal bookkeeping.
2561 * Must be called with the afs_xvcache lock at least held at
2562 * the read level. In order to do the VLRU adjustment, the xvcache lock
2563 * must be shared-- we upgrade it here.
2567 afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, afs_int32 flag)
2570 register struct vcache *tvc;
2573 AFS_STATCNT(afs_FindVCache);
2576 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2577 if (FidMatches(afid, tvc)) {
2579 /* Grab this vnode, possibly reactivating from the free list */
2582 vg = vget(AFSTOV(tvc));
2586 #endif /* AFS_OSF_ENV */
2591 /* should I have a read lock on the vnode here? */
2595 #if !defined(AFS_OSF_ENV)
2596 osi_vnhold(tvc, retry); /* already held, above */
2597 if (retry && *retry)
2601 * only move to front of vlru if we have proper vcache locking)
2603 if (flag & DO_VLRU) {
2604 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2605 refpanic("FindVC VLRU inconsistent1");
2607 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2608 refpanic("FindVC VLRU inconsistent1");
2610 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2611 refpanic("FindVC VLRU inconsistent2");
2613 UpgradeSToWLock(&afs_xvcache, 26);
2614 QRemove(&tvc->vlruq);
2615 QAdd(&VLRU, &tvc->vlruq);
2616 ConvertWToSLock(&afs_xvcache);
2617 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2618 refpanic("FindVC VLRU inconsistent1");
2620 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2621 refpanic("FindVC VLRU inconsistent2");
2623 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2624 refpanic("FindVC VLRU inconsistent3");
2630 if (flag & DO_STATS) {
2632 afs_stats_cmperf.vcacheHits++;
2634 afs_stats_cmperf.vcacheMisses++;
2635 if (afs_IsPrimaryCellNum(afid->Cell))
2636 afs_stats_cmperf.vlocalAccesses++;
2638 afs_stats_cmperf.vremoteAccesses++;
2640 #ifdef AFS_LINUX22_ENV
2641 if (tvc && (tvc->states & CStatd))
2642 vcache2inode(tvc); /* mainly to reset i_nlink */
2644 #ifdef AFS_DARWIN_ENV
2646 osi_VM_Setup(tvc, 0);
2649 } /*afs_FindVCache */
2655 * Find a vcache entry given a fid. Does a wildcard match on what we
2656 * have for the fid. If more than one entry, don't return anything.
2659 * avcp : Fill in pointer if we found one and only one.
2660 * afid : Pointer to the fid whose cache entry we desire.
2661 * retry: (SGI-specific) tell the caller to drop the lock on xvcache,
2662 * unlock the vnode, and try again.
2663 * flags: bit 1 to specify whether to compute hit statistics. Not
2664 * set if FindVCache is called as part of internal bookkeeping.
2667 * Must be called with the afs_xvcache lock at least held at
2668 * the read level. In order to do the VLRU adjustment, the xvcache lock
2669 * must be shared-- we upgrade it here.
2672 * number of matches found.
2675 int afs_duplicate_nfs_fids = 0;
2678 afs_NFSFindVCache(struct vcache **avcp, struct VenusFid *afid)
2680 register struct vcache *tvc;
2682 afs_int32 count = 0;
2683 struct vcache *found_tvc = NULL;
2685 AFS_STATCNT(afs_FindVCache);
2687 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2691 ObtainSharedLock(&afs_xvcache, 331);
2694 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2695 /* Match only on what we have.... */
2696 if (((tvc->fid.Fid.Vnode & 0xffff) == afid->Fid.Vnode)
2697 && (tvc->fid.Fid.Volume == afid->Fid.Volume)
2698 && ((tvc->fid.Fid.Unique & 0xffffff) == afid->Fid.Unique)
2699 && (tvc->fid.Cell == afid->Cell)) {
2701 /* Grab this vnode, possibly reactivating from the free list */
2704 vg = vget(AFSTOV(tvc));
2707 /* This vnode no longer exists. */
2710 #endif /* AFS_OSF_ENV */
2715 /* Drop our reference counts. */
2717 vrele(AFSTOV(found_tvc));
2719 afs_duplicate_nfs_fids++;
2720 ReleaseSharedLock(&afs_xvcache);
2728 /* should I have a read lock on the vnode here? */
2730 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2731 afs_int32 retry = 0;
2732 osi_vnhold(tvc, &retry);
2735 found_tvc = (struct vcache *)0;
2736 ReleaseSharedLock(&afs_xvcache);
2737 spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2741 #if !defined(AFS_OSF_ENV)
2742 osi_vnhold(tvc, (int *)0); /* already held, above */
2746 * We obtained the xvcache lock above.
2748 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2749 refpanic("FindVC VLRU inconsistent1");
2751 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2752 refpanic("FindVC VLRU inconsistent1");
2754 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2755 refpanic("FindVC VLRU inconsistent2");
2757 UpgradeSToWLock(&afs_xvcache, 568);
2758 QRemove(&tvc->vlruq);
2759 QAdd(&VLRU, &tvc->vlruq);
2760 ConvertWToSLock(&afs_xvcache);
2761 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2762 refpanic("FindVC VLRU inconsistent1");
2764 if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2765 refpanic("FindVC VLRU inconsistent2");
2767 if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2768 refpanic("FindVC VLRU inconsistent3");
2774 afs_stats_cmperf.vcacheHits++;
2776 afs_stats_cmperf.vcacheMisses++;
2777 if (afs_IsPrimaryCellNum(afid->Cell))
2778 afs_stats_cmperf.vlocalAccesses++;
2780 afs_stats_cmperf.vremoteAccesses++;
2782 *avcp = tvc; /* May be null */
2784 ReleaseSharedLock(&afs_xvcache);
2785 return (tvc ? 1 : 0);
2787 } /*afs_NFSFindVCache */
2795 * Initialize vcache related variables
2798 afs_vcacheInit(int astatSize)
2800 register struct vcache *tvp;
2802 #if defined(AFS_OSF_ENV)
2803 if (!afs_maxvcount) {
2804 #if defined(AFS_OSF30_ENV)
2805 afs_maxvcount = max_vnodes / 2; /* limit ourselves to half the total */
2807 afs_maxvcount = nvnode / 2; /* limit ourselves to half the total */
2809 if (astatSize < afs_maxvcount) {
2810 afs_maxvcount = astatSize;
2813 #else /* AFS_OSF_ENV */
2817 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2818 LOCK_INIT(&afs_xvcb, "afs_xvcb");
2820 #if !defined(AFS_OSF_ENV)
2821 /* Allocate and thread the struct vcache entries */
2822 tvp = (struct vcache *)afs_osi_Alloc(astatSize * sizeof(struct vcache));
2823 memset((char *)tvp, 0, sizeof(struct vcache) * astatSize);
2825 Initial_freeVCList = tvp;
2826 freeVCList = &(tvp[0]);
2827 for (i = 0; i < astatSize - 1; i++) {
2828 tvp[i].nextfree = &(tvp[i + 1]);
2830 tvp[astatSize - 1].nextfree = NULL;
2831 #ifdef KERNEL_HAVE_PIN
2832 pin((char *)tvp, astatSize * sizeof(struct vcache)); /* XXX */
2837 #if defined(AFS_SGI_ENV)
2838 for (i = 0; i < astatSize; i++) {
2839 char name[METER_NAMSZ];
2840 struct vcache *tvc = &tvp[i];
2842 tvc->v.v_number = ++afsvnumbers;
2843 tvc->vc_rwlockid = OSI_NO_LOCKID;
2844 initnsema(&tvc->vc_rwlock, 1,
2845 makesname(name, "vrw", tvc->v.v_number));
2846 #ifndef AFS_SGI53_ENV
2847 initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
2849 #ifndef AFS_SGI62_ENV
2850 initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
2851 #endif /* AFS_SGI62_ENV */
2865 shutdown_vcache(void)
2868 struct afs_cbr *tsp, *nsp;
2870 * XXX We may potentially miss some of the vcaches because if when there're no
2871 * free vcache entries and all the vcache entries are active ones then we allocate
2872 * an additional one - admittedly we almost never had that occur.
2874 #if !defined(AFS_OSF_ENV)
2875 afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2877 #ifdef KERNEL_HAVE_PIN
2878 unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2882 register struct afs_q *tq, *uq;
2883 register struct vcache *tvc;
2884 for (tq = VLRU.prev; tq != &VLRU; tq = uq) {
2888 osi_FreeSmallSpace(tvc->mvid);
2889 tvc->mvid = (struct VenusFid *)0;
2892 aix_gnode_rele(AFSTOV(tvc));
2894 if (tvc->linkData) {
2895 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2900 * Also free the remaining ones in the Cache
2902 for (i = 0; i < VCSIZE; i++) {
2903 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2905 osi_FreeSmallSpace(tvc->mvid);
2906 tvc->mvid = (struct VenusFid *)0;
2910 afs_osi_Free(tvc->v.v_gnode, sizeof(struct gnode));
2911 #ifdef AFS_AIX32_ENV
2914 vms_delete(tvc->segid);
2916 tvc->segid = tvc->vmh = NULL;
2918 osi_Panic("flushVcache: vm race");
2926 #if defined(AFS_SUN5_ENV)
2932 if (tvc->linkData) {
2933 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
2937 afs_FreeAllAxs(&(tvc->Access));
2943 * Free any leftover callback queue
2945 for (tsp = afs_cbrSpace; tsp; tsp = nsp) {
2947 afs_osi_Free((char *)tsp, AFS_NCBRS * sizeof(struct afs_cbr));
2951 #if !defined(AFS_OSF_ENV)
2952 freeVCList = Initial_freeVCList = 0;
2954 RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2955 LOCK_INIT(&afs_xvcb, "afs_xvcb");