c97e9a9ce8ab445ba61d0424f0338709c45a4f9c
[openafs.git] / src / afs / afs_vcache.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Implements:
12  * afs_FlushVCache
13  * afs_AllocCBR
14  * afs_FreeCBR
15  * afs_FlushVCBs
16  * afs_QueueVCB
17  * afs_RemoveVCB
18  * afs_NewVCache
19  * afs_FlushActiveVcaches
20  * afs_VerifyVCache2
21  * afs_WriteVCache
22  * afs_SimpleVStat
23  * afs_ProcessFS
24  * TellALittleWhiteLie
25  * afs_RemoteLookup
26  * afs_GetVCache
27  * afs_LookupVCache
28  * afs_GetRootVCache
29  * afs_FetchStatus
30  * afs_StuffVcache
31  * afs_PutVCache
32  * afs_FindVCache
33  * afs_NFSFindVCache
34  * afs_vcacheInit
35  * shutdown_vcache
36  *
37  */
38 #include <afsconfig.h>
39 #include "../afs/param.h"
40
41 RCSID("$Header$");
42
43 #include "../afs/sysincludes.h" /*Standard vendor system headers*/
44 #include "../afs/afsincludes.h" /*AFS-based standard headers*/
45 #include "../afs/afs_stats.h"
46 #include "../afs/afs_cbqueue.h"
47 #include "../afs/afs_osidnlc.h"
48
49 #ifdef AFS_OSF_ENV
50 afs_int32 afs_maxvcount = 0;            /* max number of vcache entries */
51 afs_int32 afs_vcount = 0;                       /* number of vcache in use now */
52 #if     defined(AFS_OSF30_ENV)
53 extern int max_vnodes;                  /* number of total system vnodes */
54 #else
55 extern int nvnode;                      /* number of total system vnodes */
56 #endif 
57 #ifndef AFS_OSF30_ENV
58 extern int numvnodes;                   /* number vnodes in use now */ 
59 #endif
60 #endif /* AFS_OSF_ENV */
61 #ifdef AFS_SGI_ENV
62 int afsvnumbers = 0;
63 #endif
64
65 /* Imported variables */
66 extern struct server *afs_servers[NSERVERS];
67 extern afs_rwlock_t afs_xserver;
68 extern afs_rwlock_t afs_xcbhash;
69 extern struct vcache *afs_globalVp;
70 #ifdef AFS_OSF_ENV
71 extern struct mount *afs_globalVFS;
72 extern struct vnodeops Afs_vnodeops;
73 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
74 extern struct mount *afs_globalVFS;
75 #else
76 extern struct vfs *afs_globalVFS;
77 #endif /* AFS_OSF_ENV */
78 #if     defined(AFS_DUX40_ENV)
79 extern struct vfs_ubcops afs_ubcops;
80 #endif
81 #ifdef AFS_SGI62_ENV
82 extern struct vnodeops Afs_vnodeops;
83 #endif
84 #ifdef AFS_SGI64_ENV
85 char *makesname();
86 #endif /* AFS_SGI64_ENV */
87  
88 /* Exported variables */
89 afs_rwlock_t afs_xvcache;               /*Lock: alloc new stat cache entries*/
90 afs_lock_t afs_xvcb;                    /*Lock: fids on which there are callbacks*/
91 struct vcache *freeVCList;              /*Free list for stat cache entries*/
92 struct vcache *Initial_freeVCList;      /*Initial list for above*/
93 struct afs_q VLRU;                      /*vcache LRU*/
94 afs_int32 vcachegen = 0;
95 unsigned int afs_paniconwarn = 0;
96 struct vcache *afs_vhashT[VCSIZE];
97 afs_int32 afs_bulkStatsLost;
98 int afs_norefpanic = 0;
99
100 /* Forward declarations */
101 static afs_int32 afs_QueueVCB(struct vcache *avc);
102
103
104 /*
105  * afs_FlushVCache
106  *
107  * Description:
108  *      Flush the given vcache entry.
109  *
110  * Parameters:
111  *      avc : Pointer to vcache entry to flush.
112  *      slept : Pointer to int to set 1 if we sleep/drop locks, 0 if we don't.
113  *
114  * Environment:
115  *      afs_xvcache lock must be held for writing upon entry to
116  *      prevent people from changing the vrefCount field, and to
117  *      protect the lruq and hnext fields.
118  * LOCK: afs_FlushVCache afs_xvcache W 
119  * REFCNT: vcache ref count must be zero on entry except for osf1
120  * RACE: lock is dropped and reobtained, permitting race in caller
121  */
122
123 int afs_FlushVCache(struct vcache *avc, int *slept)
124 { /*afs_FlushVCache*/
125
126     register afs_int32 i, code;
127     register struct vcache **uvc, *wvc, *tvc;
128
129     *slept = 0;
130     AFS_STATCNT(afs_FlushVCache);
131     afs_Trace2(afs_iclSetp, CM_TRACE_FLUSHV, ICL_TYPE_POINTER, avc,
132                ICL_TYPE_INT32, avc->states);
133 #ifdef  AFS_OSF_ENV
134     AFS_GUNLOCK();
135     VN_LOCK(AFSTOV(avc));
136     AFS_GLOCK();
137 #endif
138
139     code = osi_VM_FlushVCache(avc, slept);
140     if (code)
141         goto bad;
142
143     if (avc->states & CVFlushed) {
144         code = EBUSY;
145         goto bad;
146     }
147     if (avc->nextfree || !avc->vlruq.prev || !avc->vlruq.next) { /* qv afs.h */
148       refpanic ("LRU vs. Free inconsistency");
149     }
150     avc->states |= CVFlushed;
151     /* pull the entry out of the lruq and put it on the free list */
152     QRemove(&avc->vlruq);
153     avc->vlruq.prev = avc->vlruq.next = (struct afs_q *) 0;
154
155     /* keep track of # of files that we bulk stat'd, but never used
156      * before they got recycled.
157      */
158     if (avc->states & CBulkStat)
159         afs_bulkStatsLost++;
160     vcachegen++;
161     /* remove entry from the hash chain */
162     i = VCHash(&avc->fid);
163     uvc = &afs_vhashT[i];
164     for(wvc = *uvc; wvc; uvc = &wvc->hnext, wvc = *uvc) {
165         if (avc == wvc) {
166             *uvc = avc->hnext;
167             avc->hnext = (struct vcache *) NULL;
168             break;
169         }
170     }
171     if (!wvc) osi_Panic("flushvcache"); /* not in correct hash bucket */
172     if (avc->mvid) osi_FreeSmallSpace(avc->mvid);
173     avc->mvid = (struct VenusFid*)0;
174     if (avc->linkData) {
175       afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
176       avc->linkData = NULL;
177     }
178     afs_FreeAllAxs(&(avc->Access));
179
180     /* we can't really give back callbacks on RO files, since the 
181      * server only tracks them on a per-volume basis, and we don't
182      * know whether we still have some other files from the same
183      * volume. */
184     if ((avc->states & CRO) == 0 && avc->callback) {
185         afs_QueueVCB(avc);
186     }
187     ObtainWriteLock(&afs_xcbhash, 460);
188     afs_DequeueCallback(avc);  /* remove it from queued callbacks list */
189     avc->states &= ~(CStatd | CUnique);
190     ReleaseWriteLock(&afs_xcbhash);
191     afs_symhint_inval(avc);
192     if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
193       osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
194     else 
195       osi_dnlc_purgevp (avc);
196
197     /*
198      * Next, keep track of which vnodes we've deleted for create's
199      * optimistic synchronization algorithm
200      */
201     afs_allZaps++;
202     if (avc->fid.Fid.Vnode & 1) afs_oddZaps++;
203     else afs_evenZaps++;
204
205 #if     !defined(AFS_OSF_ENV)
206     /* put the entry in the free list */
207     avc->nextfree = freeVCList;
208     freeVCList = avc;
209     if (avc->vlruq.prev || avc->vlruq.next) {
210        refpanic ("LRU vs. Free inconsistency");
211     }
212 #else 
213     /* This should put it back on the vnode free list since usecount is 1 */
214     afs_vcount--;
215     vSetType(avc, VREG);
216     if (VREFCOUNT(avc) > 0) {
217         VN_UNLOCK(AFSTOV(avc));
218         AFS_RELE(AFSTOV(avc));
219     } else {
220        if (afs_norefpanic) {
221           printf ("flush vc refcnt < 1");
222           afs_norefpanic++;
223           (void) vgone(avc, VX_NOSLEEP, (struct vnodeops *) 0);
224           AFS_GLOCK();
225           VN_UNLOCK(AFSTOV(avc));
226        }
227        else osi_Panic ("flush vc refcnt < 1");
228     }
229 #endif  /* AFS_OSF_ENV */
230     avc->states |= CVFlushed;
231     return 0;
232
233 bad:
234 #ifdef  AFS_OSF_ENV
235     VN_UNLOCK(AFSTOV(avc));
236 #endif
237     return code;
238
239 } /*afs_FlushVCache*/
240
241 #ifndef AFS_SGI_ENV
242 /*
243  * afs_InactiveVCache
244  *
245  * The core of the inactive vnode op for all but IRIX.
246  */
247 void afs_InactiveVCache(struct vcache *avc, struct AFS_UCRED *acred)
248 {
249     extern afs_rwlock_t afs_xdcache, afs_xvcache;
250     
251     AFS_STATCNT(afs_inactive);
252     if (avc->states & CDirty) {
253       /* we can't keep trying to push back dirty data forever.  Give up. */
254       afs_InvalidateAllSegments(avc);  /* turns off dirty bit */
255     }
256     avc->states &= ~CMAPPED;    /* mainly used by SunOS 4.0.x */
257     avc->states &= ~CDirty;     /* Turn it off */
258     if (avc->states & CUnlinked) {
259         if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache)) { 
260             avc->states |= CUnlinkedDel;
261             return; 
262         }
263         afs_remunlink(avc, 1);  /* ignore any return code */
264     }
265
266 }
267 #endif
268
269 /*
270  * afs_AllocCBR
271  *
272  * Description: allocate a callback return structure from the
273  * free list and return it.
274  *
275  * Env: The alloc and free routines are both called with the afs_xvcb lock
276  * held, so we don't have to worry about blocking in osi_Alloc.
277  */
278 static struct afs_cbr *afs_cbrSpace = 0;
279 struct afs_cbr *afs_AllocCBR() {
280     register struct afs_cbr *tsp;
281     int i;
282
283     while (!afs_cbrSpace) {
284         if (afs_stats_cmperf.CallBackAlloced >= 2) {
285             /* don't allocate more than 2 * AFS_NCBRS for now */
286             afs_FlushVCBs(0);
287             afs_stats_cmperf.CallBackFlushes++;
288         }
289         else {
290             /* try allocating */
291             tsp = (struct afs_cbr *) afs_osi_Alloc(AFS_NCBRS * sizeof(struct afs_cbr));
292             for(i=0; i < AFS_NCBRS-1; i++) {
293                 tsp[i].next = &tsp[i+1];
294             }
295             tsp[AFS_NCBRS-1].next = 0;
296             afs_cbrSpace = tsp;
297             afs_stats_cmperf.CallBackAlloced++;
298         }
299     }
300     tsp = afs_cbrSpace;
301     afs_cbrSpace = tsp->next;
302     return tsp;
303 }
304
305 /*
306  * afs_FreeCBR
307  *
308  * Description: free a callback return structure.
309  *
310  * Parameters:
311  *      asp -- the address of the structure to free.
312  *
313  * Environment: the xvcb lock is held over these calls.
314  */
315 afs_FreeCBR(asp)
316 register struct afs_cbr *asp; {
317     asp->next = afs_cbrSpace;
318     afs_cbrSpace = asp;
319     return 0;
320 }
321
322 /*
323  * afs_FlushVCBs
324  *
325  * Description: flush all queued callbacks to all servers.
326  *
327  * Parameters: none.
328  *
329  * Environment: holds xvcb lock over RPC to guard against race conditions
330  *      when a new callback is granted for the same file later on.
331  */
332 afs_int32 afs_FlushVCBs (afs_int32 lockit) 
333 {
334     struct AFSFid tfids[AFS_MAXCBRSCALL];
335     struct AFSCallBack callBacks[1];
336     struct AFSCBFids fidArray;
337     struct AFSCBs cbArray;
338     afs_int32 code;
339     struct afs_cbr *tcbrp;
340     int tcount;
341     struct server *tsp;
342     int i;
343     struct vrequest treq;
344     struct conn *tc;
345     int safety1, safety2, safety3;
346     extern int afs_totalServers;
347     XSTATS_DECLS
348
349     if (code = afs_InitReq(&treq, &afs_osi_cred)) return code;
350     treq.flags |= O_NONBLOCK;
351
352     if (lockit) MObtainWriteLock(&afs_xvcb,273);
353     ObtainReadLock(&afs_xserver);
354     for(i=0; i<NSERVERS; i++) {
355         for(safety1 = 0, tsp = afs_servers[i];
356             tsp && safety1 < afs_totalServers+10; tsp=tsp->next, safety1++) { 
357             /* don't have any */
358             if (tsp->cbrs == (struct afs_cbr *) 0) continue;
359
360             /* otherwise, grab a block of AFS_MAXCBRSCALL from the list
361              * and make an RPC, over and over again.
362              */
363             tcount = 0; /* number found so far */
364             for (safety2 = 0; safety2 < afs_cacheStats ; safety2++) {
365                 if (tcount >= AFS_MAXCBRSCALL || !tsp->cbrs) {
366                     /* if buffer is full, or we've queued all we're going
367                      * to from this server, we should flush out the
368                      * callbacks.
369                      */
370                     fidArray.AFSCBFids_len = tcount;
371                     fidArray.AFSCBFids_val = (struct AFSFid *) tfids;
372                     cbArray.AFSCBs_len = 1;
373                     cbArray.AFSCBs_val = callBacks;
374                     callBacks[0].CallBackType = CB_EXCLUSIVE;
375                     for (safety3 = 0; safety3 < MAXHOSTS*2; safety3++) {
376                         tc = afs_ConnByHost(tsp, tsp->cell->fsport,
377                                             tsp->cell->cell, &treq, 0,
378                                             SHARED_LOCK);
379                         if (tc) {
380                           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
381                           RX_AFS_GUNLOCK();
382                           code = RXAFS_GiveUpCallBacks(tc->id, &fidArray,
383                                                        &cbArray);
384                           RX_AFS_GLOCK();
385                           XSTATS_END_TIME;
386                         }
387                         else code = -1;
388                         if (!afs_Analyze(tc, code, 0, &treq,
389                                      AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
390                                      SHARED_LOCK, tsp->cell)) {
391                            break;
392                         }
393                     }
394                     /* ignore return code, since callbacks may have
395                      * been returned anyway, we shouldn't leave them
396                      * around to be returned again.
397                      *
398                      * Next, see if we are done with this server, and if so,
399                      * break to deal with the next one.
400                      */
401                     if (!tsp->cbrs) break;
402                     tcount = 0;
403                 }       /* if to flush full buffer */
404                 /* if we make it here, we have an entry at the head of cbrs,
405                  * which we should copy to the file ID array and then free.
406                  */
407                 tcbrp = tsp->cbrs;
408                 tfids[tcount++] = tcbrp->fid;
409                 tsp->cbrs = tcbrp->next;
410                 afs_FreeCBR(tcbrp);
411             }           /* while loop for this one server */
412             if (safety2 > afs_cacheStats) {
413               afs_warn("possible internal error afs_flushVCBs (%d)\n", safety2);
414             }
415         }               /* for loop for this hash chain */
416     }                   /* loop through all hash chains */
417     if (safety1 > afs_totalServers+2)  {
418        afs_warn("AFS internal error (afs_flushVCBs) (%d > %d), continuing...\n", safety1, afs_totalServers+2);
419        if (afs_paniconwarn)
420          osi_Panic("afs_flushVCBS safety1");
421     }
422
423     ReleaseReadLock(&afs_xserver);
424     if (lockit) MReleaseWriteLock(&afs_xvcb);
425     return 0;
426 }
427
428 /*
429  * afs_QueueVCB
430  *
431  * Description:
432  *      Queue a callback on the given fid.
433  *
434  * Parameters:
435  *      avc: vcache entry
436  *
437  * Environment:
438  *      Locks the xvcb lock.
439  *      Called when the xvcache lock is already held.
440  */
441
442 static afs_int32 afs_QueueVCB(struct vcache *avc)
443 {
444     register struct server *tsp;
445     register struct afs_cbr *tcbp;
446
447     AFS_STATCNT(afs_QueueVCB);
448     /* The callback is really just a struct server ptr. */
449     tsp = (struct server *)(avc->callback);
450
451     /* we now have a pointer to the server, so we just allocate
452      * a queue entry and queue it.
453      */
454     MObtainWriteLock(&afs_xvcb,274);
455     tcbp = afs_AllocCBR();
456     tcbp->fid = avc->fid.Fid;
457     tcbp->next = tsp->cbrs;
458     tsp->cbrs = tcbp;
459
460     /* now release locks and return */
461     MReleaseWriteLock(&afs_xvcb);
462     return 0;
463 }
464
465 #ifdef AFS_LINUX22_ENV
466 /* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
467  *                               children of the dentry
468  *
469  * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
470  *          AFS_GLOCK, so it can call dput, which may call iput, but
471  *          keeps afs_xvcache exclusively.
472  *
473  * Tree traversal algorithm from fs/dcache.c: select_parent()
474  */
475 static void afs_TryFlushDcacheChildren(struct vcache *tvc)
476 {
477     struct inode *ip = AFSTOI(tvc);
478     struct dentry *this_parent;
479     struct list_head *next;
480     struct list_head *cur;
481     struct list_head *head = &ip->i_dentry;
482     struct dentry *dentry;
483     
484 restart:
485     DLOCK();
486     cur = head;
487     while ((cur = cur->next) != head) {
488         dentry = list_entry(cur, struct dentry, d_alias);
489         if (DCOUNT(dentry)) {
490             this_parent = dentry;
491         repeat:
492             next = this_parent->d_subdirs.next;
493         resume:
494             while (next && next != &this_parent->d_subdirs) {
495                 struct list_head *tmp = next;
496                 struct dentry *dchld = list_entry(tmp, struct dentry, d_child);
497                 
498                 next = tmp->next;
499                 if (!DCOUNT(dchld) && !dchld->d_inode) {
500                     DGET(dchld);
501                     AFS_GUNLOCK();
502                     DUNLOCK();
503                     d_drop(dchld);
504                     dput(dchld);
505                     AFS_GLOCK();
506                     DLOCK();
507                     goto repeat;
508                 }
509                 /*
510                  * Descend a level if the d_subdirs list is non-empty.
511                  */
512                 if (!list_empty(&dchld->d_subdirs)) {
513                     this_parent = dchld;
514                     goto repeat;
515                 }
516             }
517             
518             /*
519              * All done at this level ... ascend and resume the search.
520              */
521             if (this_parent != dentry) {
522                 next = this_parent->d_child.next;
523                 this_parent = this_parent->d_parent;
524                 goto resume;
525             }
526         }
527
528         if (!DCOUNT(dentry)) {
529             AFS_GUNLOCK();
530             DGET(dentry);
531             DUNLOCK();
532             d_drop(dentry);
533             dput(dentry);
534             AFS_GLOCK();
535             goto restart;
536         }
537     }
538     DUNLOCK();
539
540 }
541 #endif /* AFS_LINUX22_ENV */
542
543 /*
544  * afs_RemoveVCB
545  *
546  * Description:
547  *      Remove a queued callback by looking through all the servers
548  *      to see if any have this callback queued.
549  *
550  * Parameters:
551  *      afid: The fid we want cleansed of queued callbacks.
552  *
553  * Environment:
554  *      Locks xvcb and xserver locks.
555  *      Typically called with xdcache, xvcache and/or individual vcache
556  *      entries locked.
557  */
558
559 afs_RemoveVCB(afid)
560     register struct VenusFid *afid;
561
562 { /*afs_RemoveVCB*/
563
564     register int i, j;
565     register struct server *tsp;
566     register struct afs_cbr *tcbrp;
567     struct afs_cbr **lcbrpp;
568
569     AFS_STATCNT(afs_RemoveVCB);
570     MObtainWriteLock(&afs_xvcb,275);
571     ObtainReadLock(&afs_xserver);
572     for(i=0;i<NSERVERS;i++) {
573         for(tsp=afs_servers[i]; tsp; tsp=tsp->next) {
574             /* if cell is known, and is wrong, then skip this server */
575             if (tsp->cell && tsp->cell->cell != afid->Cell) continue;
576
577             /*
578              * Otherwise, iterate through file IDs we're sending to the
579              * server.
580              */
581             lcbrpp = &tsp->cbrs;        /* first queued return callback */
582             for(tcbrp = *lcbrpp; tcbrp; lcbrpp = &tcbrp->next, tcbrp = *lcbrpp) {
583                 if (afid->Fid.Volume == tcbrp->fid.Volume &&
584                     afid->Fid.Unique == tcbrp->fid.Unique &&
585                     afid->Fid.Vnode == tcbrp->fid.Vnode) {
586                     *lcbrpp = tcbrp->next;      /* unthread from list */
587                     afs_FreeCBR(tcbrp);
588                     goto done;
589                 }
590             }
591         }
592     }
593   done:
594     ReleaseReadLock(&afs_xserver);
595     MReleaseWriteLock(&afs_xvcb);
596     return 0;
597
598 } /*afs_RemoveVCB*/
599
600
601 /*
602  * afs_NewVCache
603  *
604  * Description:
605  *      This routine is responsible for allocating a new cache entry
606  *      from the free list.  It formats the cache entry and inserts it
607  *      into the appropriate hash tables.  It must be called with
608  *      afs_xvcache write-locked so as to prevent several processes from
609  *      trying to create a new cache entry simultaneously.
610  *
611  * Parameters:
612  *      afid  : The file id of the file whose cache entry is being
613  *              created.
614  */
615 /* LOCK: afs_NewVCache  afs_xvcache W */ 
616 struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
617                              afs_int32 lockit, afs_int32 locktype)
618 {
619     struct vcache *tvc;
620     afs_int32 i;
621     afs_int32 anumber = VCACHE_FREE;
622 #ifdef  AFS_AIX_ENV
623     struct gnode *gnodepnt;
624 #endif
625 #ifdef  AFS_MACH_ENV
626     struct vm_info * vm_info_ptr;
627 #endif /* AFS_MACH_ENV */
628 #ifdef  AFS_OSF_ENV
629     struct vcache *nvc;
630 #endif  /* AFS_OSF_ENV */
631     struct afs_q *tq, *uq;
632     int code, fv_slept;
633
634     AFS_STATCNT(afs_NewVCache);
635 #ifdef  AFS_OSF_ENV
636 #ifdef  AFS_OSF30_ENV
637     if (afs_vcount >= afs_maxvcount) 
638 #else
639     /*
640      * If we are using > 33 % of the total system vnodes for AFS vcache
641      * entries or we are using the maximum number of vcache entries,
642      * then free some.  (if our usage is > 33% we should free some, if
643      * our usage is > afs_maxvcount, set elsewhere to 0.5*nvnode, 
644      * we _must_ free some -- no choice).
645      */
646     if ( (( 3 * afs_vcount ) > nvnode) || ( afs_vcount >= afs_maxvcount ))
647 #endif
648        {
649          struct afs_q *tq, *uq;
650          int i; char *panicstr;
651
652          i = 0;
653          for(tq = VLRU.prev; tq != &VLRU && anumber > 0; tq = uq) {
654             tvc = QTOV(tq);
655             uq = QPrev(tq);
656             if (tvc->states & CVFlushed) 
657                  refpanic ("CVFlushed on VLRU");
658             else if (i++ > afs_maxvcount)
659                  refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)");
660             else if (QNext(uq) != tq)
661                  refpanic ("VLRU inconsistent");
662             else if (VREFCOUNT(tvc) < 1) 
663                  refpanic ("refcnt 0 on VLRU");
664
665             if ( VREFCOUNT(tvc) == 1   &&   tvc->opens == 0 
666                 && (tvc->states & CUnlinkedDel) == 0) {
667                 code = afs_FlushVCache(tvc, &fv_slept);
668                 if (code == 0) {
669                   anumber--;
670                 }
671                 if (fv_slept) {
672                   uq = VLRU.prev;
673                   i = 0;
674                   continue;  /* start over - may have raced. */
675                 }
676             }
677             if (tq == uq) break;
678          }
679          if (anumber == VCACHE_FREE) {
680             printf("NewVCache: warning none freed, using %d of %d\n", 
681                    afs_vcount, afs_maxvcount);
682             if (afs_vcount >= afs_maxvcount) {
683                 osi_Panic("NewVCache - none freed");
684                 /* XXX instead of panicing, should do afs_maxvcount++ 
685                    and magic up another one */
686             }
687          }
688       }
689
690     AFS_GUNLOCK();
691     if (getnewvnode(MOUNT_AFS, &Afs_vnodeops, &nvc)) {
692         /* What should we do ???? */
693         osi_Panic("afs_NewVCache: no more vnodes");
694     }
695     AFS_GLOCK();
696
697     tvc = nvc;
698     tvc->nextfree = (struct vcache *)0; 
699     afs_vcount++;
700 #else   /* AFS_OSF_ENV */
701     /* pull out a free cache entry */
702     if (!freeVCList) {
703         i = 0;
704         for(tq = VLRU.prev; (anumber > 0) && (tq != &VLRU); tq = uq) {
705            tvc = QTOV(tq);
706            uq = QPrev(tq);
707
708            if (tvc->states & CVFlushed)
709                 refpanic("CVFlushed on VLRU");
710            else if (i++ > 2*afs_cacheStats) /* even allowing for a few xallocs...*/
711                 refpanic("Increase -stat parameter of afsd(VLRU cycle?)");
712            else if (QNext(uq) != tq)
713                 refpanic("VLRU inconsistent");
714
715 #ifdef AFS_DARWIN_ENV
716            if (tvc->opens == 0 && ((tvc->states & CUnlinkedDel) == 0) &&
717                 VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
718                osi_VM_TryReclaim(tvc, &fv_slept);
719                if (fv_slept) {
720                   uq = VLRU.prev;
721                   i = 0;
722                   continue;  /* start over - may have raced. */
723                }
724             }
725 #endif
726 #if defined(AFS_FBSD_ENV)
727            if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
728                && (tvc->states & CUnlinkedDel) == 0) {
729                if (!(VOP_LOCK(&tvc->v, LK_EXCLUSIVE, curproc))) {
730                   if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
731                       && (tvc->states & CUnlinkedDel) == 0) {
732                       VREFCOUNT_DEC(tvc);
733                       AFS_GUNLOCK(); /* perhaps inline inactive for locking */
734                       VOP_INACTIVE(&tvc->v, curproc);
735                       AFS_GLOCK();
736                   } else {
737                      VOP_UNLOCK(&tvc->v, 0, curproc);
738                   }
739                }
740            }
741 #endif
742 #if defined(AFS_LINUX22_ENV)
743             if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0)
744                 afs_TryFlushDcacheChildren(tvc);
745 #endif
746
747            if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
748                && (tvc->states & CUnlinkedDel) == 0) {
749                 code = afs_FlushVCache(tvc, &fv_slept);
750                 if (code == 0) {
751                   anumber--;
752                 }
753                 if (fv_slept) {
754                   uq = VLRU.prev;
755                   i = 0;
756                   continue;  /* start over - may have raced. */
757                 }
758            } 
759            if (tq == uq ) break;
760         }
761     }
762     if (!freeVCList) {
763         /* none free, making one is better than a panic */
764         afs_stats_cmperf.vcacheXAllocs++;       /* count in case we have a leak */
765         tvc = (struct vcache *) afs_osi_Alloc(sizeof (struct vcache));
766 #ifdef  AFS_AIX32_ENV
767         pin((char *)tvc, sizeof(struct vcache));        /* XXX */
768 #endif
769 #ifdef  AFS_MACH_ENV
770         /* In case it still comes here we need to fill this */
771         tvc->v.v_vm_info = VM_INFO_NULL;
772         vm_info_init(tvc->v.v_vm_info);
773         /* perhaps we should also do close_flush on non-NeXT mach systems;
774          * who knows; we don't currently have the sources.
775          */
776 #endif /* AFS_MACH_ENV */
777 #if defined(AFS_SGI_ENV)
778         { char name[METER_NAMSZ];
779         memset(tvc, 0, sizeof(struct vcache));
780         tvc->v.v_number = ++afsvnumbers;
781         tvc->vc_rwlockid = OSI_NO_LOCKID;
782         initnsema(&tvc->vc_rwlock, 1, makesname(name, "vrw", tvc->v.v_number));
783 #ifndef AFS_SGI53_ENV
784         initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
785 #endif
786 #ifndef AFS_SGI62_ENV
787         initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
788 #endif
789         }
790 #endif /* AFS_SGI_ENV */
791     }
792     else {
793         tvc = freeVCList;   /* take from free list */
794         freeVCList = tvc->nextfree;
795         tvc->nextfree = (struct vcache *)0;
796     }
797 #endif  /* AFS_OSF_ENV */
798
799 #ifdef  AFS_MACH_ENV
800     vm_info_ptr = tvc->v.v_vm_info;
801 #endif /* AFS_MACH_ENV */
802
803 #if !defined(AFS_SGI_ENV) && !defined(AFS_OSF_ENV)
804     memset((char *)tvc, 0, sizeof(struct vcache));
805 #else
806     tvc->uncred = 0;
807 #endif
808
809     RWLOCK_INIT(&tvc->lock, "vcache lock");
810 #if     defined(AFS_SUN5_ENV)
811     RWLOCK_INIT(&tvc->vlock, "vcache vlock");
812 #endif /* defined(AFS_SUN5_ENV) */
813
814 #ifdef  AFS_MACH_ENV
815     tvc->v.v_vm_info = vm_info_ptr;
816     tvc->v.v_vm_info->pager = MEMORY_OBJECT_NULL;
817 #endif /* AFS_MACH_ENV */
818     tvc->parentVnode = 0;
819     tvc->mvid = (struct VenusFid *) 0;
820     tvc->linkData = (char *) 0;
821     tvc->cbExpires = 0;
822     tvc->opens = 0;
823     tvc->execsOrWriters = 0;
824     tvc->flockCount = 0;
825     tvc->anyAccess = 0;
826     tvc->states = 0;
827     tvc->last_looker = 0;
828     tvc->fid = *afid;
829     tvc->asynchrony = -1;
830     tvc->vc_error = 0;
831     afs_symhint_inval(tvc);
832 #ifdef AFS_TEXT_ENV
833     tvc->flushDV.low = tvc->flushDV.high =  AFS_MAXDV;
834 #endif
835     hzero(tvc->mapDV);
836     tvc->truncPos = AFS_NOTRUNC;        /* don't truncate until we need to */
837     hzero(tvc->m.DataVersion);          /* in case we copy it into flushDV */
838 #ifdef  AFS_OSF_ENV
839     /* Hold it for the LRU (should make count 2) */
840     VN_HOLD(AFSTOV(tvc));
841 #else   /* AFS_OSF_ENV */
842     VREFCOUNT_SET(tvc, 1);      /* us */
843 #endif  /* AFS_OSF_ENV */
844 #ifdef  AFS_AIX32_ENV
845     LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
846     tvc->vmh = tvc->segid = NULL;
847     tvc->credp = NULL;
848 #endif
849 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
850 #if     defined(AFS_SUN5_ENV)
851     rw_init(&tvc->rwlock, "vcache rwlock", RW_DEFAULT, NULL);
852
853 #if     defined(AFS_SUN55_ENV)
854         /* This is required if the kaio (kernel aynchronous io)
855         ** module is installed. Inside the kernel, the function
856         ** check_vp( common/os/aio.c) checks to see if the kernel has 
857         ** to provide asynchronous io for this vnode. This
858         ** function extracts the device number by following the
859         ** v_data field of the vnode. If we do not set this field
860         ** then the system panics. The  value of the v_data field
861         ** is not really important for AFS vnodes because the kernel
862         ** does not do asynchronous io for regular files. Hence,
863         ** for the time being, we fill up the v_data field with the
864         ** vnode pointer itself. */
865     tvc->v.v_data = (char *)tvc;
866 #endif /* AFS_SUN55_ENV */
867 #endif
868     afs_BozonInit(&tvc->pvnLock, tvc);
869 #endif
870
871     tvc->Access = NULL;
872     tvc->callback = serverp;    /* to minimize chance that clear
873                                    request is lost */
874     /* initialize vnode data, note vrefCount is v.v_count */
875 #ifdef  AFS_AIX_ENV
876     /* Don't forget to free the gnode space */
877     tvc->v.v_gnode = gnodepnt = (struct gnode *) osi_AllocSmallSpace(sizeof(struct gnode));
878     memset((char *)gnodepnt, 0, sizeof(struct gnode));
879 #endif
880 #ifdef AFS_SGI64_ENV
881     memset((void*)&(tvc->vc_bhv_desc), 0, sizeof(tvc->vc_bhv_desc));
882     bhv_desc_init(&(tvc->vc_bhv_desc), tvc, tvc, &Afs_vnodeops);
883 #ifdef AFS_SGI65_ENV
884     vn_bhv_head_init(&(tvc->v.v_bh), "afsvp");
885     vn_bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
886 #else
887     bhv_head_init(&(tvc->v.v_bh));
888     bhv_insert_initial(&(tvc->v.v_bh), &(tvc->vc_bhv_desc));
889 #endif
890 #ifdef AFS_SGI65_ENV
891     tvc->v.v_mreg = tvc->v.v_mregb = (struct pregion*)tvc;
892 #ifdef VNODE_TRACING
893     tvc->v.v_trace = ktrace_alloc(VNODE_TRACE_SIZE, 0);
894 #endif
895     init_bitlock(&tvc->v.v_pcacheflag, VNODE_PCACHE_LOCKBIT, "afs_pcache",
896                  tvc->v.v_number);
897     init_mutex(&tvc->v.v_filocksem, MUTEX_DEFAULT, "afsvfl", (long)tvc);
898     init_mutex(&tvc->v.v_buf_lock, MUTEX_DEFAULT, "afsvnbuf", (long)tvc);
899 #endif
900     vnode_pcache_init(&tvc->v);
901 #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK)
902     /* Above define is never true execpt in SGI test kernels. */
903     init_bitlock(&(tvc->v.v_flag, VLOCK, "vnode", tvc->v.v_number);
904 #endif
905 #ifdef INTR_KTHREADS
906     AFS_VN_INIT_BUF_LOCK(&(tvc->v));
907 #endif
908 #else
909     SetAfsVnode(AFSTOV(tvc));
910 #endif /* AFS_SGI64_ENV */
911 #ifdef AFS_DARWIN_ENV
912     tvc->v.v_ubcinfo = UBC_INFO_NULL;
913     lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
914     cache_purge(AFSTOV(tvc)); 
915     tvc->v.v_data=tvc;
916     tvc->v.v_tag=VT_AFS;
917     /* VLISTNONE(&tvc->v); */
918     tvc->v.v_freelist.tqe_next=0;
919     tvc->v.v_freelist.tqe_prev=(struct vnode **)0xdeadb;
920     /*tvc->vrefCount++;*/
921 #endif 
922 #ifdef AFS_FBSD_ENV
923     lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
924     cache_purge(AFSTOV(tvc)); 
925     tvc->v.v_data=tvc;
926     tvc->v.v_tag=VT_AFS;
927     tvc->v.v_usecount++; /* steal an extra ref for now so vfree never happens */
928                          /* This extra ref is dealt with above... */
929 #endif
930     /*
931      * The proper value for mvstat (for root fids) is setup by the caller.
932      */
933     tvc->mvstat = 0;           
934     if (afid->Fid.Vnode == 1 && afid->Fid.Unique == 1)
935         tvc->mvstat = 2;   
936     if (afs_globalVFS == 0) osi_Panic("afs globalvfs");
937     vSetVfsp(tvc, afs_globalVFS);
938     vSetType(tvc, VREG);
939 #ifdef  AFS_AIX_ENV
940     tvc->v.v_vfsnext = afs_globalVFS->vfs_vnodes;   /* link off vfs */
941     tvc->v.v_vfsprev = NULL;
942     afs_globalVFS->vfs_vnodes = &tvc->v;
943     if (tvc->v.v_vfsnext != NULL)
944         tvc->v.v_vfsnext->v_vfsprev = &tvc->v;
945     tvc->v.v_next = gnodepnt->gn_vnode;  /*Single vnode per gnode for us!*/
946     gnodepnt->gn_vnode = &tvc->v;
947 #endif
948 #ifdef  AFS_DEC_ENV
949     tvc->v.g_dev = ((struct mount *)afs_globalVFS->vfs_data)->m_dev;
950 #endif
951 #if     defined(AFS_DUX40_ENV)
952     insmntque(tvc, afs_globalVFS, &afs_ubcops);
953 #else
954 #ifdef  AFS_OSF_ENV
955     /* Is this needed??? */
956     insmntque(tvc, afs_globalVFS);
957 #endif  /* AFS_OSF_ENV */
958 #endif  /* AFS_DUX40_ENV */
959 #if defined(AFS_SGI_ENV)
960     VN_SET_DPAGES(&(tvc->v), (struct pfdat*)NULL);
961     osi_Assert((tvc->v.v_flag & VINACT) == 0);
962     tvc->v.v_flag = 0;
963     osi_Assert(VN_GET_PGCNT(&(tvc->v)) == 0);
964     osi_Assert(tvc->mapcnt == 0 && tvc->vc_locktrips == 0);
965     osi_Assert(tvc->vc_rwlockid == OSI_NO_LOCKID);
966     osi_Assert(tvc->v.v_filocks == NULL);
967 #if !defined(AFS_SGI65_ENV)
968     osi_Assert(tvc->v.v_filocksem == NULL);
969 #endif
970     osi_Assert(tvc->cred == NULL);
971 #ifdef AFS_SGI64_ENV
972     vnode_pcache_reinit(&tvc->v);
973     tvc->v.v_rdev = NODEV;
974 #endif
975     vn_initlist((struct vnlist *)&tvc->v);
976     tvc->lastr = 0;
977 #endif /* AFS_SGI_ENV */
978 #if defined(AFS_LINUX22_ENV)
979     {
980         struct inode *ip = AFSTOI(tvc);
981         sema_init(&ip->i_sem, 1);
982 #if defined(AFS_LINUX24_ENV)
983         sema_init(&ip->i_zombie, 1);
984         init_waitqueue_head(&ip->i_wait);
985         spin_lock_init(&ip->i_data.i_shared_lock);
986 #ifdef STRUCT_ADDRESS_SPACE_HAS_PAGE_LOCK
987         spin_lock_init(&ip->i_data.page_lock);
988 #endif
989         INIT_LIST_HEAD(&ip->i_data.clean_pages);
990         INIT_LIST_HEAD(&ip->i_data.dirty_pages);
991         INIT_LIST_HEAD(&ip->i_data.locked_pages);
992         INIT_LIST_HEAD(&ip->i_dirty_buffers);
993 #ifdef STRUCT_INODE_HAS_I_DIRTY_DATA_BUFFERS
994         INIT_LIST_HEAD(&ip->i_dirty_data_buffers);
995 #endif
996 #ifdef STRUCT_INODE_HAS_I_DEVICES
997         INIT_LIST_HEAD(&ip->i_devices);
998 #endif
999         ip->i_data.host = (void*) ip;
1000         ip->i_mapping = &ip->i_data;
1001 #ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
1002         init_rwsem(&ip->i_truncate_sem);
1003 #endif
1004 #else
1005         sema_init(&ip->i_atomic_write, 1);
1006         init_waitqueue(&ip->i_wait);
1007 #endif
1008         INIT_LIST_HEAD(&ip->i_hash);
1009         INIT_LIST_HEAD(&ip->i_dentry);
1010         if (afs_globalVFS) {
1011             ip->i_dev = afs_globalVFS->s_dev;
1012             ip->i_sb = afs_globalVFS;
1013         }
1014      }
1015 #endif
1016     tvc->h1.dchint = 0;
1017     osi_dnlc_purgedp(tvc);  /* this may be overkill */
1018     memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
1019     memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
1020     tvc->slocks = (struct SimpleLocks *)0;
1021     i = VCHash(afid);
1022
1023     tvc->hnext = afs_vhashT[i];
1024     afs_vhashT[i] = tvc;
1025     if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1026        refpanic ("NewVCache VLRU inconsistent");
1027     }
1028     QAdd(&VLRU, &tvc->vlruq);                           /* put in lruq */
1029     if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1030        refpanic ("NewVCache VLRU inconsistent2");
1031     }
1032     if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
1033        refpanic ("NewVCache VLRU inconsistent3");
1034     }
1035     if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
1036        refpanic ("NewVCache VLRU inconsistent4");
1037     }
1038     vcachegen++;
1039
1040     return tvc;
1041
1042 } /*afs_NewVCache*/
1043
1044
1045 /*
1046  * afs_FlushActiveVcaches
1047  *
1048  * Description:
1049  *      ???
1050  *
1051  * Parameters:
1052  *      doflocks : Do we handle flocks?
1053  */
1054 /* LOCK: afs_FlushActiveVcaches afs_xvcache N */
1055 void
1056 afs_FlushActiveVcaches(doflocks)
1057     register afs_int32 doflocks;
1058
1059 { /*afs_FlushActiveVcaches*/
1060
1061     register struct vcache *tvc;
1062     register int i;
1063     register struct conn *tc;
1064     register afs_int32 code;
1065     register struct AFS_UCRED *cred;
1066     struct vrequest treq, ureq;
1067     struct AFSVolSync tsync;
1068     int didCore;
1069     XSTATS_DECLS
1070
1071     AFS_STATCNT(afs_FlushActiveVcaches);
1072     ObtainReadLock(&afs_xvcache);
1073     for(i=0;i<VCSIZE;i++) {
1074         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
1075             if (doflocks && tvc->flockCount != 0) {
1076                 /* if this entry has an flock, send a keep-alive call out */
1077                 osi_vnhold(tvc, 0);
1078                 ReleaseReadLock(&afs_xvcache);
1079                 ObtainWriteLock(&tvc->lock,51);
1080                 do {
1081                     afs_InitReq(&treq, &afs_osi_cred);
1082                     treq.flags |= O_NONBLOCK;
1083
1084                     tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
1085                     if (tc) {
1086                       XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
1087                       RX_AFS_GUNLOCK();
1088                       code =
1089                             RXAFS_ExtendLock(tc->id,
1090                                              (struct AFSFid *) &tvc->fid.Fid,
1091                                              &tsync);
1092                       RX_AFS_GLOCK();
1093                       XSTATS_END_TIME;
1094                     }
1095                     else code = -1;
1096                 } while
1097                     (afs_Analyze(tc, code, &tvc->fid, &treq,
1098                                  AFS_STATS_FS_RPCIDX_EXTENDLOCK,
1099                                  SHARED_LOCK, (struct cell *)0));
1100
1101                 ReleaseWriteLock(&tvc->lock);
1102                 ObtainReadLock(&afs_xvcache);
1103                 AFS_FAST_RELE(tvc);
1104             }
1105             didCore = 0;
1106             if ((tvc->states & CCore) || (tvc->states & CUnlinkedDel)) {
1107                 /*
1108                  * Don't let it evaporate in case someone else is in
1109                  * this code.  Also, drop the afs_xvcache lock while
1110                  * getting vcache locks.
1111                  */
1112                 osi_vnhold(tvc,0);
1113                 ReleaseReadLock(&afs_xvcache);
1114 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1115                 afs_BozonLock(&tvc->pvnLock, tvc);
1116 #endif
1117 #if defined(AFS_SGI_ENV)
1118                 /*
1119                  * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
1120                  */
1121                 osi_Assert(VREFCOUNT(tvc) > 0);
1122                 AFS_RWLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1123 #endif
1124                 ObtainWriteLock(&tvc->lock,52);
1125                 if (tvc->states & CCore) {
1126                     tvc->states &= ~CCore;
1127                     /* XXXX Find better place-holder for cred XXXX */
1128                     cred = (struct AFS_UCRED *) tvc->linkData;
1129                     tvc->linkData = (char *) 0; /* XXX */
1130                     afs_InitReq(&ureq, cred);
1131                     afs_Trace2(afs_iclSetp, CM_TRACE_ACTCCORE,
1132                                ICL_TYPE_POINTER, tvc,
1133                                ICL_TYPE_INT32, tvc->execsOrWriters);
1134                     code = afs_StoreOnLastReference(tvc, &ureq);
1135                     ReleaseWriteLock(&tvc->lock);
1136 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1137                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1138 #endif
1139                     hzero(tvc->flushDV);
1140                     osi_FlushText(tvc);
1141                     didCore = 1;
1142                     if (code && code != VNOVNODE) {
1143                         afs_StoreWarn(code, tvc->fid.Fid.Volume,
1144                                       /* /dev/console */ 1);
1145                     }
1146                 } else if (tvc->states & CUnlinkedDel) {
1147                     /*
1148                      * Ignore errors 
1149                      */
1150                     ReleaseWriteLock(&tvc->lock);
1151 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1152                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1153 #endif
1154 #if defined(AFS_SGI_ENV)
1155                     AFS_RWUNLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1156 #endif
1157                     afs_remunlink(tvc, 0);
1158 #if defined(AFS_SGI_ENV)
1159                     AFS_RWLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1160 #endif
1161                 }
1162                 else {
1163                     /* lost (or won, perhaps) the race condition */
1164                     ReleaseWriteLock(&tvc->lock);
1165 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1166                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1167 #endif
1168                 }
1169 #if defined(AFS_SGI_ENV)
1170                 AFS_RWUNLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1171 #endif
1172                 ObtainReadLock(&afs_xvcache);
1173                 AFS_FAST_RELE(tvc);
1174                 if (didCore) {
1175 #ifdef  AFS_GFS_ENV
1176                     VREFCOUNT_DEC(tvc);
1177 #else
1178                     AFS_RELE(AFSTOV(tvc));
1179 #endif
1180                     /* Matches write code setting CCore flag */
1181                     crfree(cred);
1182                 }
1183             }          
1184 #ifdef AFS_DARWIN_ENV
1185             if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
1186                 if (tvc->opens) panic("flushactive open, hasubc, but refcnt 1");
1187                 osi_VM_TryReclaim(tvc,0);
1188             }
1189 #endif
1190         }
1191     }
1192     ReleaseReadLock(&afs_xvcache);
1193
1194 } /*afs_FlushActiveVcaches*/
1195
1196
1197 /*
1198  * afs_VerifyVCache
1199  *
1200  * Description:
1201  *      Make sure a cache entry is up-to-date status-wise.
1202  * 
1203  * NOTE: everywhere that calls this can potentially be sped up
1204  *       by checking CStatd first, and avoiding doing the InitReq
1205  *       if this is up-to-date.
1206  *
1207  *  Anymore, the only places that call this KNOW already that the 
1208  *  vcache is not up-to-date, so we don't screw around.
1209  *
1210  * Parameters:
1211  *      avc  : Ptr to vcache entry to verify.
1212  *      areq : ???
1213  */
1214
1215 int afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq)
1216 {
1217     register struct vcache *tvc;
1218
1219     AFS_STATCNT(afs_VerifyVCache);
1220
1221 #if defined(AFS_OSF_ENV)
1222     ObtainReadLock(&avc->lock);
1223     if (afs_IsWired(avc)) {
1224         ReleaseReadLock(&avc->lock);
1225         return 0;
1226     }
1227     ReleaseReadLock(&avc->lock);
1228 #endif /* AFS_OSF_ENV */
1229     /* otherwise we must fetch the status info */
1230
1231     ObtainWriteLock(&avc->lock,53);
1232     if (avc->states & CStatd) {
1233         ReleaseWriteLock(&avc->lock);
1234         return 0;
1235     }
1236     ObtainWriteLock(&afs_xcbhash, 461);
1237     avc->states &= ~( CStatd | CUnique );   
1238     avc->callback = (struct server *)0;
1239     afs_DequeueCallback(avc);
1240     ReleaseWriteLock(&afs_xcbhash);
1241     ReleaseWriteLock(&avc->lock);
1242
1243     /* since we've been called back, or the callback has expired, 
1244      * it's possible that the contents of this directory, or this 
1245      * file's name have changed, thus invalidating the dnlc contents.
1246      */
1247     if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
1248       osi_dnlc_purgedp (avc);
1249     else
1250       osi_dnlc_purgevp (avc);
1251     
1252     /* fetch the status info */
1253     tvc = afs_GetVCache(&avc->fid, areq, (afs_int32*)0, avc, READ_LOCK);
1254     if (!tvc) return ENOENT;
1255     /* Put it back; caller has already incremented vrefCount */
1256     afs_PutVCache(tvc, READ_LOCK);
1257     return 0;
1258
1259 } /*afs_VerifyVCache*/
1260
1261
1262 /*
1263  * afs_SimpleVStat
1264  *
1265  * Description:
1266  *      Simple copy of stat info into cache.
1267  *
1268  * Parameters:
1269  *      avc   : Ptr to vcache entry involved.
1270  *      astat : Ptr to stat info to copy.
1271  *
1272  * Environment:
1273  *      Nothing interesting.
1274  *
1275  * Callers:  as of 1992-04-29, only called by WriteVCache
1276  */
1277 static void
1278 afs_SimpleVStat(avc, astat, areq)
1279     register struct vcache *avc;
1280     register struct AFSFetchStatus *astat;
1281     struct vrequest *areq;
1282 { /*afs_SimpleVStat*/
1283
1284     afs_size_t length;
1285     AFS_STATCNT(afs_SimpleVStat);
1286
1287 #ifdef AFS_SGI_ENV
1288     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1289         && !AFS_VN_MAPPED((vnode_t*)avc))
1290 #else
1291     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc))
1292 #endif
1293
1294         {
1295 #ifdef AFS_64BIT_ClIENT
1296             FillInt64(length, astat->Length_hi, astat->Length);
1297 #else /* AFS_64BIT_CLIENT */
1298             length = astat->Length;
1299 #endif /* AFS_64BIT_CLIENT */
1300 #if defined(AFS_SGI_ENV)
1301             osi_Assert((valusema(&avc->vc_rwlock) <= 0) &&
1302                    (OSI_GET_LOCKID() == avc->vc_rwlockid));
1303             if (length < avc->m.Length) {
1304                 vnode_t *vp = (vnode_t *)avc;
1305                 
1306                 osi_Assert(WriteLocked(&avc->lock));
1307                 ReleaseWriteLock(&avc->lock);
1308                 AFS_GUNLOCK();
1309                 PTOSSVP(vp, (off_t)length, (off_t)MAXLONG);
1310                 AFS_GLOCK();
1311                 ObtainWriteLock(&avc->lock,67);
1312             }
1313 #endif
1314             /* if writing the file, don't fetch over this value */
1315             afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT,
1316                        ICL_TYPE_POINTER, avc,
1317                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1318                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1319             avc->m.Length = length;
1320             avc->m.Date = astat->ClientModTime;
1321         }
1322     avc->m.Owner = astat->Owner;
1323     avc->m.Group = astat->Group;
1324     avc->m.Mode = astat->UnixModeBits;
1325     if (vType(avc) == VREG) {
1326         avc->m.Mode |= S_IFREG;
1327     }
1328     else if (vType(avc) == VDIR) {
1329         avc->m.Mode |= S_IFDIR;
1330     }
1331     else if (vType(avc) == VLNK) {
1332
1333
1334
1335         avc->m.Mode |= S_IFLNK;
1336         if ((avc->m.Mode & 0111) == 0) avc->mvstat = 1;
1337     }
1338     if (avc->states & CForeign) {
1339       struct axscache *ac;
1340         avc->anyAccess = astat->AnonymousAccess;
1341 #ifdef badidea
1342         if ((astat->CallerAccess & ~astat->AnonymousAccess)) 
1343          /*   USED TO SAY : 
1344           * Caller has at least one bit not covered by anonymous, and
1345           * thus may have interesting rights.
1346           *
1347           * HOWEVER, this is a really bad idea, because any access query
1348           * for bits which aren't covered by anonymous, on behalf of a user
1349           * who doesn't have any special rights, will result in an answer of 
1350           * the form "I don't know, lets make a FetchStatus RPC and find out!"
1351           * It's an especially bad idea under Ultrix, since (due to the lack of
1352           * a proper access() call) it must perform several afs_access() calls 
1353           * in order to create magic mode bits that vary according to who makes
1354           * the call.  In other words, _every_ stat() generates a test for 
1355           * writeability...
1356           */
1357 #endif /* badidea */
1358           if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1359             ac->axess =  astat->CallerAccess;
1360           else  /* not found, add a new one if possible */
1361             afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1362     }
1363
1364
1365 } /*afs_SimpleVStat*/
1366
1367
1368 /*
1369  * afs_WriteVCache
1370  *
1371  * Description:
1372  *      Store the status info *only* back to the server for a
1373  *      fid/vrequest.
1374  *
1375  * Parameters:
1376  *      avc     : Ptr to the vcache entry.
1377  *      astatus : Ptr to the status info to store.
1378  *      areq    : Ptr to the associated vrequest.
1379  *
1380  * Environment:
1381  *      Must be called with a shared lock held on the vnode.
1382  */
1383
1384 afs_WriteVCache(avc, astatus, areq)
1385     register struct vcache *avc;
1386     register struct AFSStoreStatus *astatus;
1387     struct vrequest *areq;
1388
1389 { /*afs_WriteVCache*/
1390   afs_int32 code;
1391   struct conn *tc;
1392     struct AFSFetchStatus OutStatus;
1393     struct AFSVolSync tsync;
1394     XSTATS_DECLS
1395
1396     AFS_STATCNT(afs_WriteVCache);
1397     afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
1398                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
1399
1400     do {
1401         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1402         if (tc) {
1403           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
1404           RX_AFS_GUNLOCK();
1405           code = RXAFS_StoreStatus(tc->id,
1406                                    (struct AFSFid *) &avc->fid.Fid,
1407                                    astatus, &OutStatus, &tsync);
1408           RX_AFS_GLOCK();
1409           XSTATS_END_TIME;
1410         }
1411         else code = -1;
1412     } while
1413         (afs_Analyze(tc, code, &avc->fid, areq,
1414                      AFS_STATS_FS_RPCIDX_STORESTATUS,
1415                      SHARED_LOCK, (struct cell *)0));
1416
1417     UpgradeSToWLock(&avc->lock,20);
1418     if (code == 0) {
1419         /* success, do the changes locally */
1420         afs_SimpleVStat(avc, &OutStatus, areq);
1421         /*
1422          * Update the date, too.  SimpleVStat didn't do this, since
1423          * it thought we were doing this after fetching new status
1424          * over a file being written.
1425          */
1426         avc->m.Date = OutStatus.ClientModTime;
1427     }
1428     else {
1429         /* failure, set up to check with server next time */
1430         ObtainWriteLock(&afs_xcbhash, 462);
1431         afs_DequeueCallback(avc);
1432         avc->states &= ~( CStatd | CUnique);  /* turn off stat valid flag */
1433         ReleaseWriteLock(&afs_xcbhash);
1434         if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
1435           osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
1436     }
1437     ConvertWToSLock(&avc->lock);
1438     return code;
1439
1440 } /*afs_WriteVCache*/
1441
1442 /*
1443  * afs_ProcessFS
1444  *
1445  * Description:
1446  *      Copy astat block into vcache info
1447  *
1448  * Parameters:
1449  *      avc   : Ptr to vcache entry.
1450  *      astat : Ptr to stat block to copy in.
1451  *      areq  : Ptr to associated request.
1452  *
1453  * Environment:
1454  *      Must be called under a write lock
1455  *
1456  * Note: this code may get dataversion and length out of sync if the file has
1457  *       been modified.  This is less than ideal.  I haven't thought about
1458  *       it sufficiently to be certain that it is adequate.
1459  */
1460 void
1461 afs_ProcessFS(avc, astat, areq)
1462     register struct vcache *avc;
1463     struct vrequest *areq;
1464     register struct AFSFetchStatus *astat;
1465
1466 { /*afs_ProcessFS*/
1467
1468     register int i;
1469     afs_size_t length;
1470     AFS_STATCNT(afs_ProcessFS);
1471
1472 #ifdef AFS_64BIT_CLIENT
1473     FillInt64(length, astat->Length_hi, astat->Length);
1474 #else /* AFS_64BIT_CLIENT */
1475     length = astat->Length;
1476 #endif /* AFS_64BIT_CLIENT */
1477     /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
1478      * number for each bulk status request. Under no circumstances
1479      * should afs_DoBulkStat store a sequence number if the new
1480      * length will be ignored when afs_ProcessFS is called with
1481      * new stats. If you change the following conditional then you
1482      * also need to change the conditional in afs_DoBulkStat.  */
1483 #ifdef AFS_SGI_ENV
1484     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1485         && !AFS_VN_MAPPED((vnode_t*)avc))
1486 #else
1487     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc))
1488 #endif
1489         {
1490             /* if we're writing or mapping this file, don't fetch over these
1491              *  values.
1492              */
1493             afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
1494                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1495                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1496             avc->m.Length = length;
1497             avc->m.Date = astat->ClientModTime;
1498         }
1499     hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
1500     avc->m.Owner = astat->Owner;
1501     avc->m.Mode = astat->UnixModeBits;
1502     avc->m.Group = astat->Group;
1503     avc->m.LinkCount = astat->LinkCount;
1504     if (astat->FileType == File) {
1505         vSetType(avc, VREG);
1506         avc->m.Mode |= S_IFREG;
1507     }
1508     else if (astat->FileType == Directory) {
1509         vSetType(avc, VDIR);
1510         avc->m.Mode |= S_IFDIR;
1511     }
1512     else if (astat->FileType == SymbolicLink) {
1513         if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
1514             vSetType(avc, VDIR);
1515             avc->m.Mode |= S_IFDIR;
1516         } else {
1517             vSetType(avc, VLNK);
1518             avc->m.Mode |= S_IFLNK;
1519         }
1520         if ((avc->m.Mode & 0111) == 0) {
1521             avc->mvstat = 1;
1522         }
1523     }
1524     avc->anyAccess = astat->AnonymousAccess;
1525 #ifdef badidea
1526     if ((astat->CallerAccess & ~astat->AnonymousAccess)) 
1527       /*   USED TO SAY : 
1528        * Caller has at least one bit not covered by anonymous, and
1529        * thus may have interesting rights.
1530        *
1531        * HOWEVER, this is a really bad idea, because any access query
1532        * for bits which aren't covered by anonymous, on behalf of a user
1533        * who doesn't have any special rights, will result in an answer of 
1534        * the form "I don't know, lets make a FetchStatus RPC and find out!"
1535        * It's an especially bad idea under Ultrix, since (due to the lack of
1536        * a proper access() call) it must perform several afs_access() calls 
1537        * in order to create magic mode bits that vary according to who makes
1538        * the call.  In other words, _every_ stat() generates a test for 
1539        * writeability...
1540        */
1541 #endif /* badidea */
1542       {
1543         struct axscache *ac;
1544         if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1545           ac->axess =  astat->CallerAccess;
1546         else  /* not found, add a new one if possible */
1547           afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1548       }
1549
1550 #ifdef AFS_LINUX22_ENV
1551     vcache2inode(avc);    /* Set the inode attr cache */
1552 #endif
1553
1554 } /*afs_ProcessFS*/
1555
1556
1557 afs_RemoteLookup(afid, areq, name, nfid, OutStatusp, CallBackp, serverp, tsyncp)
1558     register struct VenusFid *afid;
1559     struct vrequest *areq;
1560     char *name;
1561     struct VenusFid *nfid;
1562     struct AFSFetchStatus *OutStatusp;
1563     struct AFSCallBack *CallBackp;
1564     struct server **serverp;
1565     struct AFSVolSync *tsyncp;
1566 {
1567     afs_int32 code, i;
1568     register struct vcache *tvc;
1569     struct volume *tvp;
1570     afs_uint32 start;
1571     register struct conn *tc;
1572     struct AFSFetchStatus OutDirStatus;
1573     XSTATS_DECLS
1574
1575     if (!name) name = "";       /* XXX */
1576     do {
1577         tc = afs_Conn(afid, areq, SHARED_LOCK);
1578         if (tc) {
1579             if (serverp) *serverp = tc->srvr->server;
1580             start = osi_Time();
1581             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
1582             RX_AFS_GUNLOCK();
1583             code = RXAFS_Lookup(tc->id, (struct AFSFid *) &afid->Fid, name,
1584                                 (struct AFSFid *) &nfid->Fid, 
1585                                 OutStatusp, &OutDirStatus, CallBackp, tsyncp);
1586             RX_AFS_GLOCK();
1587             XSTATS_END_TIME;
1588         } else 
1589             code = -1;
1590     } while
1591         (afs_Analyze(tc, code, afid, areq,
1592                      AFS_STATS_FS_RPCIDX_XLOOKUP,
1593                      SHARED_LOCK, (struct cell *)0));
1594
1595     return code;
1596 }
1597
1598
1599 /*
1600  * afs_GetVCache
1601  *
1602  * Description:
1603  *      Given a file id and a vrequest structure, fetch the status
1604  *      information associated with the file.
1605  *
1606  * Parameters:
1607  *      afid : File ID.
1608  *      areq : Ptr to associated vrequest structure, specifying the
1609  *              user whose authentication tokens will be used.
1610  *      avc  : caller may already have a vcache for this file, which is 
1611  *             already held.
1612  *
1613  * Environment:
1614  *      The cache entry is returned with an increased vrefCount field.
1615  *      The entry must be discarded by calling afs_PutVCache when you
1616  *      are through using the pointer to the cache entry.
1617  *
1618  *      You should not hold any locks when calling this function, except
1619  *      locks on other vcache entries.  If you lock more than one vcache
1620  *      entry simultaneously, you should lock them in this order:
1621  *
1622  *          1. Lock all files first, then directories.
1623  *          2.  Within a particular type, lock entries in Fid.Vnode order.
1624  *  
1625  *      This locking hierarchy is convenient because it allows locking
1626  *      of a parent dir cache entry, given a file (to check its access
1627  *      control list).  It also allows renames to be handled easily by
1628  *      locking directories in a constant order.
1629  * NB.  NewVCache -> FlushVCache presently (4/10/95) drops the xvcache lock.
1630  */
1631 struct vcache *afs_GetVCache(afid, areq, cached, avc, locktype)
1632     register struct VenusFid *afid;
1633     struct vrequest *areq;
1634     afs_int32 *cached;
1635     afs_int32 locktype;
1636     struct vcache *avc; /* might have a vcache structure already, which must
1637                          * already be held by the caller */
1638 { /*afs_GetVCache*/
1639
1640     afs_int32 code, i, newvcache=0;
1641     register struct vcache *tvc;
1642     struct volume *tvp;
1643     afs_int32 retry;
1644
1645     AFS_STATCNT(afs_GetVCache);
1646
1647     if (cached) *cached = 0;            /* Init just in case */
1648
1649 loop:
1650     ObtainSharedLock(&afs_xvcache,5); 
1651
1652     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_STATS | DO_VLRU );
1653     if (tvc && retry) {
1654 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1655         ReleaseSharedLock(&afs_xvcache);
1656         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1657         goto loop;
1658 #endif
1659    }
1660    
1661     if (tvc) {
1662       if (cached) 
1663         *cached = 1;
1664       if (tvc->states & CStatd) {               
1665         ReleaseSharedLock(&afs_xvcache);
1666         return tvc;
1667       }
1668     }
1669     else {      
1670         UpgradeSToWLock(&afs_xvcache,21);
1671
1672         /* no cache entry, better grab one */
1673         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
1674         newvcache = 1;
1675
1676         ConvertWToSLock(&afs_xvcache);
1677         afs_stats_cmperf.vcacheMisses++;
1678     }
1679
1680     ReleaseSharedLock(&afs_xvcache);
1681
1682     ObtainWriteLock(&tvc->lock,54);
1683
1684     if (tvc->states & CStatd) {
1685 #ifdef AFS_LINUX22_ENV
1686         vcache2inode(tvc);
1687 #endif
1688         ReleaseWriteLock(&tvc->lock);
1689 #ifdef AFS_DARWIN_ENV
1690         osi_VM_Setup(tvc);
1691 #endif
1692         return tvc;
1693     }
1694
1695 #if defined(AFS_OSF_ENV)
1696       if (afs_IsWired(tvc)) {
1697           ReleaseWriteLock(&tvc->lock);
1698           return tvc;
1699       }
1700 #endif /* AFS_OSF_ENV */
1701
1702     ObtainWriteLock(&afs_xcbhash, 464);
1703     tvc->states &= ~CUnique;   
1704     tvc->callback = 0;
1705     afs_DequeueCallback(tvc);
1706     ReleaseWriteLock(&afs_xcbhash);
1707
1708     /* It is always appropriate to throw away all the access rights? */
1709     afs_FreeAllAxs(&(tvc->Access));
1710     tvp = afs_GetVolume(afid, areq, READ_LOCK);   /* copy useful per-volume info */
1711     if (tvp) {
1712         if ((tvp->states & VForeign)) {
1713             if (newvcache) tvc->states |= CForeign;
1714             if (newvcache && (tvp->rootVnode == afid->Fid.Vnode) 
1715                 && (tvp->rootUnique == afid->Fid.Unique)) {
1716                 tvc->mvstat = 2;
1717               }
1718         }
1719         if (tvp->states & VRO) tvc->states |= CRO;
1720         if (tvp->states & VBackup) tvc->states |= CBackup;
1721         /* now copy ".." entry back out of volume structure, if necessary */
1722         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
1723             if (!tvc->mvid)
1724                 tvc->mvid = (struct VenusFid *)
1725                     osi_AllocSmallSpace(sizeof(struct VenusFid));
1726             *tvc->mvid = tvp->dotdot;
1727         }
1728         afs_PutVolume(tvp, READ_LOCK);
1729     }
1730
1731     /* stat the file */
1732     afs_RemoveVCB(afid);
1733     {
1734         struct AFSFetchStatus OutStatus;
1735
1736         if (afs_DynrootNewVnode(tvc, &OutStatus)) {
1737             afs_ProcessFS(tvc, &OutStatus, areq);
1738             tvc->states |= CStatd | CUnique;
1739             code = 0;
1740         } else {
1741             code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
1742         }
1743     }
1744
1745     if (code) {
1746         ReleaseWriteLock(&tvc->lock);
1747
1748         ObtainReadLock(&afs_xvcache);
1749         AFS_FAST_RELE(tvc);
1750         ReleaseReadLock(&afs_xvcache);
1751         return (struct vcache *) 0;
1752     }
1753
1754     ReleaseWriteLock(&tvc->lock);
1755 #ifdef AFS_DARWIN_ENV
1756     osi_VM_Setup(avc);
1757 #endif
1758     return tvc;
1759
1760 } /*afs_GetVCache*/
1761
1762
1763
1764 struct vcache *afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
1765                                 afs_int32 *cached, afs_int32 locktype,
1766                                 struct vcache *adp, char *aname)
1767 {
1768     afs_int32 code, now, newvcache=0, hash;
1769     struct VenusFid nfid;
1770     register struct vcache *tvc;
1771     struct volume *tvp;
1772     struct AFSFetchStatus OutStatus;
1773     struct AFSCallBack CallBack;
1774     struct AFSVolSync tsync;
1775     struct server *serverp = 0;
1776     afs_int32 origCBs;
1777     afs_int32 retry;
1778
1779     AFS_STATCNT(afs_GetVCache);
1780     if (cached) *cached = 0;            /* Init just in case */
1781
1782   loop1:
1783     ObtainReadLock(&afs_xvcache);
1784     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_STATS /* no vlru */);
1785
1786     if (tvc) {
1787       ReleaseReadLock(&afs_xvcache);
1788       if (retry) {
1789 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1790         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1791         goto loop1;
1792 #endif
1793       }
1794       ObtainReadLock(&tvc->lock);
1795
1796       if (tvc->states & CStatd) {
1797         if (cached) {
1798           *cached = 1;
1799         }
1800         ReleaseReadLock(&tvc->lock);
1801         return tvc;
1802       } 
1803       tvc->states &= ~CUnique;   
1804
1805         ReleaseReadLock(&tvc->lock);
1806         ObtainReadLock(&afs_xvcache);
1807         AFS_FAST_RELE(tvc);
1808     }  /* if (tvc) */
1809
1810     ReleaseReadLock(&afs_xvcache);
1811
1812     /* lookup the file */
1813     nfid = *afid;
1814     now = osi_Time();
1815     origCBs = afs_allCBs;       /* if anything changes, we don't have a cb */
1816     code = afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
1817                             &serverp, &tsync);  
1818
1819   loop2:
1820     ObtainSharedLock(&afs_xvcache,6);
1821     tvc = afs_FindVCache(&nfid, 0, 0, &retry, DO_VLRU /* no xstats now*/);
1822     if (tvc && retry) {
1823 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1824       ReleaseSharedLock(&afs_xvcache);
1825       spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1826       goto loop2;
1827 #endif
1828     }
1829
1830     if (!tvc) {
1831         /* no cache entry, better grab one */
1832         UpgradeSToWLock(&afs_xvcache,22);
1833         tvc = afs_NewVCache(&nfid, (struct server *)0, 1, WRITE_LOCK);
1834         newvcache = 1;
1835         ConvertWToSLock(&afs_xvcache);
1836     }
1837
1838     ReleaseSharedLock(&afs_xvcache);
1839     ObtainWriteLock(&tvc->lock,55);
1840  
1841     /* It is always appropriate to throw away all the access rights? */
1842     afs_FreeAllAxs(&(tvc->Access));
1843     tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-vol info */
1844     if (tvp) {
1845         if ((tvp->states & VForeign)) {
1846             if (newvcache) tvc->states |= CForeign;
1847             if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
1848                 && (tvp->rootUnique == afid->Fid.Unique))
1849                 tvc->mvstat = 2;
1850         }
1851         if (tvp->states & VRO) tvc->states |= CRO;
1852         if (tvp->states & VBackup) tvc->states |= CBackup;
1853         /* now copy ".." entry back out of volume structure, if necessary */
1854         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
1855             if (!tvc->mvid)
1856                 tvc->mvid = (struct VenusFid *)
1857                     osi_AllocSmallSpace(sizeof(struct VenusFid));
1858             *tvc->mvid = tvp->dotdot;
1859         }
1860     }
1861
1862     if (code) {
1863         ObtainWriteLock(&afs_xcbhash, 465);
1864         afs_DequeueCallback(tvc);
1865         tvc->states &= ~( CStatd | CUnique );
1866         ReleaseWriteLock(&afs_xcbhash);
1867         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1868           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1869         if ( tvp )
1870                 afs_PutVolume(tvp, READ_LOCK);
1871         ReleaseWriteLock(&tvc->lock);
1872         ObtainReadLock(&afs_xvcache);
1873         AFS_FAST_RELE(tvc);
1874         ReleaseReadLock(&afs_xvcache);
1875         return (struct vcache *) 0;
1876     }
1877
1878     ObtainWriteLock(&afs_xcbhash, 466);
1879     if (origCBs == afs_allCBs) {
1880         if (CallBack.ExpirationTime) {
1881             tvc->callback = serverp;
1882             tvc->cbExpires = CallBack.ExpirationTime+now;
1883             tvc->states |= CStatd | CUnique;
1884             tvc->states &= ~CBulkFetching;
1885             afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvp);
1886         } else if (tvc->states & CRO) {
1887             /* adapt gives us an hour. */
1888             tvc->cbExpires = 3600+osi_Time(); /*XXX*/
1889             tvc->states |= CStatd | CUnique;
1890             tvc->states &= ~CBulkFetching;
1891             afs_QueueCallback(tvc, CBHash(3600), tvp); 
1892         } else {
1893             tvc->callback = (struct server *)0;
1894             afs_DequeueCallback(tvc);
1895             tvc->states &= ~(CStatd | CUnique);   
1896             if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1897               osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1898         }
1899     } else {
1900         afs_DequeueCallback(tvc);
1901         tvc->states &= ~CStatd; 
1902         tvc->states &= ~CUnique;   
1903         tvc->callback = (struct server *)0;
1904         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1905           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1906     }   
1907     ReleaseWriteLock(&afs_xcbhash);
1908     if ( tvp )
1909         afs_PutVolume(tvp, READ_LOCK);
1910     afs_ProcessFS(tvc, &OutStatus, areq);
1911
1912     ReleaseWriteLock(&tvc->lock);
1913 #ifdef AFS_DARWIN_ENV
1914     osi_VM_Setup(tvc);
1915 #endif
1916     return tvc;
1917
1918 }
1919
1920 struct vcache *afs_GetRootVCache(struct VenusFid *afid,
1921                                  struct vrequest *areq, afs_int32 *cached,
1922                                  struct volume *tvolp, afs_int32 locktype)
1923 {
1924     afs_int32 code, i, newvcache = 0, haveStatus = 0;
1925     afs_int32 getNewFid = 0;
1926     afs_uint32 start;
1927     struct VenusFid nfid;
1928     register struct vcache *tvc;
1929     struct server *serverp = 0;
1930     struct AFSFetchStatus OutStatus;
1931     struct AFSCallBack CallBack;
1932     struct AFSVolSync tsync;
1933     int origCBs;
1934
1935     start = osi_Time();
1936
1937  newmtpt:
1938     if (!tvolp->rootVnode || getNewFid) {
1939         struct VenusFid tfid;
1940
1941         tfid = *afid;
1942         tfid.Fid.Vnode = 0;     /* Means get rootfid of volume */
1943         origCBs = afs_allCBs; /* ignore InitCallBackState */
1944         code = afs_RemoteLookup(&tfid, areq, (char *)0, &nfid, 
1945                                 &OutStatus, &CallBack, &serverp, &tsync);
1946         if (code) {
1947             return (struct vcache *)0;
1948         }
1949 /*      ReleaseReadLock(&tvolp->lock);           */
1950         ObtainWriteLock(&tvolp->lock,56);
1951         tvolp->rootVnode = afid->Fid.Vnode = nfid.Fid.Vnode;
1952         tvolp->rootUnique = afid->Fid.Unique = nfid.Fid.Unique;
1953         ReleaseWriteLock(&tvolp->lock); 
1954 /*      ObtainReadLock(&tvolp->lock);*/
1955         haveStatus = 1;
1956     } else {
1957         afid->Fid.Vnode = tvolp->rootVnode;
1958         afid->Fid.Unique = tvolp->rootUnique;
1959     }   
1960     
1961     ObtainSharedLock(&afs_xvcache,7);
1962     i = VCHash(afid);
1963     for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1964         if (!FidCmp(&(tvc->fid), afid)) {
1965 #ifdef  AFS_OSF_ENV
1966             /* Grab this vnode, possibly reactivating from the free list */
1967             /* for the present (95.05.25) everything on the hash table is 
1968              * definitively NOT in the free list -- at least until afs_reclaim
1969              * can be safely implemented */
1970             int vg;
1971             AFS_GUNLOCK();
1972             vg = vget(AFSTOV(tvc));   /* this bumps ref count */
1973             AFS_GLOCK();
1974             if (vg)
1975                 continue;
1976 #endif  /* AFS_OSF_ENV */
1977             break;
1978         }
1979     }
1980
1981     if (!haveStatus && (!tvc || !(tvc->states & CStatd))) {
1982         /* Mount point no longer stat'd or unknown. FID may have changed. */
1983 #ifdef AFS_OSF_ENV
1984         if (tvc)
1985             AFS_RELE(tvc);
1986 #endif
1987         tvc = (struct vcache*)0;
1988         getNewFid = 1;
1989         ReleaseSharedLock(&afs_xvcache);
1990         goto newmtpt;
1991     }
1992
1993     if (!tvc) {
1994         UpgradeSToWLock(&afs_xvcache,23);
1995         /* no cache entry, better grab one */
1996         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
1997         newvcache = 1;
1998         afs_stats_cmperf.vcacheMisses++;
1999     }
2000     else {
2001         if (cached) *cached = 1;
2002         afs_stats_cmperf.vcacheHits++;
2003 #ifdef  AFS_OSF_ENV
2004         /* we already bumped the ref count in the for loop above */
2005 #else   /* AFS_OSF_ENV */
2006         osi_vnhold(tvc,0);
2007 #endif
2008         UpgradeSToWLock(&afs_xvcache,24);
2009         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2010            refpanic ("GRVC VLRU inconsistent0");
2011         }
2012         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2013            refpanic ("GRVC VLRU inconsistent1");
2014         }
2015         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2016            refpanic ("GRVC VLRU inconsistent2");
2017         }
2018         QRemove(&tvc->vlruq);           /* move to lruq head */
2019         QAdd(&VLRU, &tvc->vlruq);
2020         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2021            refpanic ("GRVC VLRU inconsistent3");
2022         }
2023         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2024            refpanic ("GRVC VLRU inconsistent4");
2025         }
2026         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2027            refpanic ("GRVC VLRU inconsistent5");
2028         }
2029         vcachegen++;
2030     }
2031
2032     ReleaseWriteLock(&afs_xvcache);
2033
2034     if (tvc->states & CStatd) {
2035         return tvc;
2036     } else {  
2037
2038       ObtainReadLock(&tvc->lock);
2039       tvc->states &= ~CUnique;   
2040       tvc->callback = (struct server *)0;              /* redundant, perhaps */
2041       ReleaseReadLock(&tvc->lock);
2042     }
2043
2044     ObtainWriteLock(&tvc->lock,57);
2045
2046     /* It is always appropriate to throw away all the access rights? */
2047     afs_FreeAllAxs(&(tvc->Access));
2048
2049     if (newvcache) tvc->states |= CForeign;
2050     if (tvolp->states & VRO) tvc->states |= CRO;
2051     if (tvolp->states & VBackup) tvc->states |= CBackup;
2052     /* now copy ".." entry back out of volume structure, if necessary */
2053     if (newvcache && (tvolp->rootVnode == afid->Fid.Vnode) 
2054         && (tvolp->rootUnique == afid->Fid.Unique)) {
2055         tvc->mvstat = 2;
2056     }
2057     if (tvc->mvstat == 2  && tvolp->dotdot.Fid.Volume != 0) {
2058         if (!tvc->mvid)
2059             tvc->mvid = (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
2060         *tvc->mvid = tvolp->dotdot;
2061     }
2062
2063     /* stat the file */
2064     afs_RemoveVCB(afid);
2065
2066     if (!haveStatus) {
2067         struct VenusFid tfid;
2068
2069         tfid = *afid;
2070         tfid.Fid.Vnode = 0;     /* Means get rootfid of volume */
2071         origCBs = afs_allCBs; /* ignore InitCallBackState */
2072         code = afs_RemoteLookup(&tfid, areq, (char *)0, &nfid, &OutStatus,
2073                                 &CallBack, &serverp, &tsync);
2074     }
2075
2076     if (code) {
2077         ObtainWriteLock(&afs_xcbhash, 467);
2078         afs_DequeueCallback(tvc);
2079         tvc->callback = (struct server *)0;
2080         tvc->states &= ~(CStatd|CUnique);  
2081         ReleaseWriteLock(&afs_xcbhash);
2082         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2083           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2084         ReleaseWriteLock(&tvc->lock);
2085         ObtainReadLock(&afs_xvcache);
2086         AFS_FAST_RELE(tvc);
2087         ReleaseReadLock(&afs_xvcache);
2088         return (struct vcache *) 0;
2089     }
2090         
2091     ObtainWriteLock(&afs_xcbhash, 468);
2092     if (origCBs == afs_allCBs) {
2093         tvc->states |= CTruth;
2094         tvc->callback = serverp;
2095         if (CallBack.ExpirationTime != 0) {  
2096             tvc->cbExpires = CallBack.ExpirationTime+start;
2097             tvc->states |= CStatd;
2098             tvc->states &= ~CBulkFetching;
2099             afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvolp);
2100         } else if (tvc->states & CRO) {
2101             /* adapt gives us an hour. */
2102             tvc->cbExpires = 3600+osi_Time(); /*XXX*/
2103             tvc->states |= CStatd;
2104             tvc->states &= ~CBulkFetching;
2105             afs_QueueCallback(tvc, CBHash(3600), tvolp);
2106         }
2107     } else {
2108         afs_DequeueCallback(tvc);
2109         tvc->callback = (struct server *)0;
2110         tvc->states &= ~(CStatd | CUnique);
2111         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2112           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2113     }
2114     ReleaseWriteLock(&afs_xcbhash);
2115     afs_ProcessFS(tvc, &OutStatus, areq);
2116     
2117     ReleaseWriteLock(&tvc->lock);
2118     return tvc;
2119 }
2120
2121
2122
2123 /*
2124  * must be called with avc write-locked 
2125  * don't absolutely have to invalidate the hint unless the dv has 
2126  * changed, but be sure to get it right else there will be consistency bugs.
2127  */
2128 afs_int32 afs_FetchStatus(struct vcache *avc, struct VenusFid *afid,
2129                       struct vrequest *areq, struct AFSFetchStatus *Outsp)
2130 {
2131   int code;
2132   afs_uint32 start;
2133   register struct conn *tc;
2134   struct AFSCallBack CallBack;
2135   struct AFSVolSync tsync;
2136   struct volume*    volp;
2137   XSTATS_DECLS
2138
2139     do {
2140         tc = afs_Conn(afid, areq, SHARED_LOCK);
2141         avc->quick.stamp = 0; avc->h1.dchint = NULL; /* invalidate hints */
2142         if (tc) {
2143             avc->callback = tc->srvr->server;
2144             start = osi_Time();
2145             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
2146             RX_AFS_GUNLOCK();
2147             code = RXAFS_FetchStatus(tc->id,
2148                                      (struct AFSFid *) &afid->Fid,
2149                                      Outsp, &CallBack, &tsync);
2150             RX_AFS_GLOCK();
2151
2152             XSTATS_END_TIME;
2153
2154         }
2155         else code = -1;
2156     } while
2157         (afs_Analyze(tc, code, afid, areq,
2158                      AFS_STATS_FS_RPCIDX_FETCHSTATUS,
2159                      SHARED_LOCK, (struct cell *)0));
2160
2161 if (!code) {
2162   afs_ProcessFS(avc, Outsp, areq);
2163   volp = afs_GetVolume(afid, areq, READ_LOCK);
2164   ObtainWriteLock(&afs_xcbhash, 469);
2165   avc->states |= CTruth;
2166   if (avc->callback /* check for race */) {
2167     if (CallBack.ExpirationTime != 0) {  
2168       avc->cbExpires = CallBack.ExpirationTime+start;
2169       avc->states |= CStatd;
2170       avc->states &= ~CBulkFetching;
2171       afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
2172     }
2173     else if (avc->states & CRO) 
2174       { /* ordinary callback on a read-only volume -- AFS 3.2 style */
2175         avc->cbExpires = 3600+start;
2176         avc->states |= CStatd;
2177         avc->states &= ~CBulkFetching;
2178         afs_QueueCallback(avc, CBHash(3600), volp);
2179        }
2180     else {
2181       afs_DequeueCallback(avc);
2182       avc->callback = (struct server *)0;
2183       avc->states &= ~(CStatd|CUnique);  
2184       if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
2185         osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
2186     }
2187   }
2188   else {
2189     afs_DequeueCallback(avc);
2190     avc->callback = (struct server *)0;
2191     avc->states &= ~(CStatd|CUnique);  
2192     if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
2193       osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
2194   }
2195   ReleaseWriteLock(&afs_xcbhash);
2196   if ( volp )
2197     afs_PutVolume(volp, READ_LOCK);
2198 }
2199 else {     /* used to undo the local callback, but that's too extreme. 
2200             * There are plenty of good reasons that fetchstatus might return 
2201             * an error, such as EPERM.  If we have the vnode cached, statd, 
2202             * with callback, might as well keep track of the fact that we 
2203             * don't have access...
2204             */
2205      if (code == EPERM || code == EACCES) {
2206        struct axscache *ac;
2207        if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
2208          ac->axess = 0;
2209        else  /* not found, add a new one if possible */
2210          afs_AddAxs(avc->Access, areq->uid, 0);
2211      }
2212 }
2213 return code;
2214 }
2215
2216 #if 0
2217 /*
2218  * afs_StuffVcache
2219  *
2220  * Description:
2221  *      Stuff some information into the vcache for the given file.
2222  *
2223  * Parameters:
2224  *      afid      : File in question.
2225  *      OutStatus : Fetch status on the file.
2226  *      CallBack  : Callback info.
2227  *      tc        : RPC connection involved.
2228  *      areq      : vrequest involved.
2229  *
2230  * Environment:
2231  *      Nothing interesting.
2232  */
2233 void
2234 afs_StuffVcache(afid, OutStatus, CallBack, tc, areq)
2235     register struct VenusFid *afid;
2236     struct AFSFetchStatus *OutStatus;
2237     struct AFSCallBack *CallBack;
2238     register struct conn *tc;
2239     struct vrequest *areq;
2240
2241 { /*afs_StuffVcache*/
2242
2243     register afs_int32 code, i, newvcache=0;
2244     register struct vcache *tvc;
2245     struct AFSVolSync tsync;
2246     struct volume *tvp;
2247     struct axscache *ac;
2248     afs_int32 retry;
2249
2250     AFS_STATCNT(afs_StuffVcache);
2251 #ifdef IFS_VCACHECOUNT
2252     ifs_gvcachecall++;
2253 #endif
2254
2255   loop:
2256     ObtainSharedLock(&afs_xvcache,8);
2257
2258     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_VLRU /* no stats */);
2259     if (tvc && retry) {
2260 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2261         ReleaseSharedLock(&afs_xvcache);
2262         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2263         goto loop;
2264 #endif
2265    }
2266
2267     if (!tvc) {
2268         /* no cache entry, better grab one */
2269         UpgradeSToWLock(&afs_xvcache,25);
2270         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
2271         newvcache = 1;
2272         ConvertWToSLock(&afs_xvcache);
2273     }
2274
2275     ReleaseSharedLock(&afs_xvcache);
2276     ObtainWriteLock(&tvc->lock,58);
2277
2278     tvc->states &= ~CStatd;
2279     if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2280       osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2281
2282     /* Is it always appropriate to throw away all the access rights? */
2283     afs_FreeAllAxs(&(tvc->Access));
2284
2285     /*Copy useful per-volume info*/
2286     tvp = afs_GetVolume(afid, areq, READ_LOCK);
2287     if (tvp) {
2288         if (newvcache && (tvp->states & VForeign)) tvc->states |= CForeign;
2289         if (tvp->states & VRO) tvc->states |= CRO;
2290         if (tvp->states & VBackup) tvc->states |= CBackup;
2291         /*
2292          * Now, copy ".." entry back out of volume structure, if
2293          * necessary
2294          */
2295         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
2296             if (!tvc->mvid) tvc->mvid =
2297                 (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
2298             *tvc->mvid = tvp->dotdot;
2299         }
2300     }
2301     /* store the stat on the file */
2302     afs_RemoveVCB(afid);
2303     afs_ProcessFS(tvc, OutStatus, areq);
2304     tvc->callback = tc->srvr->server;
2305
2306     /* we use osi_Time twice below.  Ideally, we would use the time at which 
2307      * the FetchStatus call began, instead, but we don't have it here.  So we
2308      * make do with "now".  In the CRO case, it doesn't really matter. In 
2309      * the other case, we hope that the difference between "now" and when the 
2310      * call actually began execution on the server won't be larger than the
2311      * padding which the server keeps.  Subtract 1 second anyway, to be on 
2312      * the safe side.  Can't subtract more because we don't know how big
2313      * ExpirationTime is.  Possible consistency problems may arise if the call
2314      * timeout period becomes longer than the server's expiration padding.  */
2315     ObtainWriteLock(&afs_xcbhash, 470);
2316     if (CallBack->ExpirationTime != 0) {
2317         tvc->cbExpires = CallBack->ExpirationTime+osi_Time()-1; 
2318         tvc->states |= CStatd;
2319         tvc->states &= ~CBulkFetching;
2320         afs_QueueCallback(tvc, CBHash(CallBack->ExpirationTime), tvp);
2321         }
2322     else if (tvc->states & CRO) {
2323        /* old-fashioned AFS 3.2 style */
2324        tvc->cbExpires = 3600+osi_Time(); /*XXX*/
2325        tvc->states |= CStatd;
2326        tvc->states &= ~CBulkFetching;
2327        afs_QueueCallback(tvc, CBHash(3600), tvp); 
2328      }
2329     else {
2330       afs_DequeueCallback(tvc);
2331       tvc->callback = (struct server *)0;
2332       tvc->states &= ~(CStatd|CUnique);  
2333       if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2334         osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2335     }
2336     ReleaseWriteLock(&afs_xcbhash);
2337     if ( tvp )
2338         afs_PutVolume(tvp, READ_LOCK);
2339         
2340     /* look in per-pag cache */
2341       if (tvc->Access && (ac = afs_FindAxs(tvc->Access, areq->uid)))
2342           ac->axess = OutStatus->CallerAccess;   /* substitute pags */
2343       else  /* not found, add a new one if possible */
2344           afs_AddAxs(tvc->Access, areq->uid, OutStatus->CallerAccess);
2345
2346     ReleaseWriteLock(&tvc->lock);
2347     afs_Trace4(afs_iclSetp, CM_TRACE_STUFFVCACHE, ICL_TYPE_POINTER, tvc,
2348                ICL_TYPE_POINTER, tvc->callback, ICL_TYPE_INT32, tvc->cbExpires,
2349                ICL_TYPE_INT32, tvc->cbExpires-osi_Time());
2350     /*
2351      * Release ref count... hope this guy stays around...
2352      */
2353     afs_PutVCache(tvc, WRITE_LOCK);
2354 } /*afs_StuffVcache*/
2355 #endif
2356
2357 /*
2358  * afs_PutVCache
2359  *
2360  * Description:
2361  *      Decrements the reference count on a cache entry.
2362  *
2363  * Parameters:
2364  *      avc : Pointer to the cache entry to decrement.
2365  *
2366  * Environment:
2367  *      Nothing interesting.
2368  */
2369 void
2370 afs_PutVCache(avc, locktype)
2371     register struct vcache *avc;
2372     afs_int32 locktype;
2373 { /*afs_PutVCache*/
2374
2375     AFS_STATCNT(afs_PutVCache);
2376     /*
2377      * Can we use a read lock here?
2378      */
2379     ObtainReadLock(&afs_xvcache);
2380     AFS_FAST_RELE(avc);
2381     ReleaseReadLock(&afs_xvcache);
2382 } /*afs_PutVCache*/
2383
2384 /*
2385  * afs_FindVCache
2386  *
2387  * Description:
2388  *      Find a vcache entry given a fid.
2389  *
2390  * Parameters:
2391  *      afid : Pointer to the fid whose cache entry we desire.
2392  *      retry: (SGI-specific) tell the caller to drop the lock on xvcache, 
2393  *             unlock the vnode, and try again.
2394  *      flags: bit 1 to specify whether to compute hit statistics.  Not
2395  *             set if FindVCache is called as part of internal bookkeeping.
2396  *
2397  * Environment:
2398  *      Must be called with the afs_xvcache lock at least held at
2399  *      the read level.  In order to do the VLRU adjustment, the xvcache lock
2400  *      must be shared-- we upgrade it here.
2401  */
2402
2403 struct vcache *afs_FindVCache(struct VenusFid *afid, afs_int32 lockit,
2404                               afs_int32 locktype, afs_int32 *retry, afs_int32 flag)
2405 {
2406
2407     register struct vcache *tvc;
2408     afs_int32 i;
2409
2410     AFS_STATCNT(afs_FindVCache);
2411
2412     i = VCHash(afid);
2413     for(tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2414         if (FidMatches(afid, tvc)) {
2415 #ifdef  AFS_OSF_ENV
2416             /* Grab this vnode, possibly reactivating from the free list */
2417             int vg;
2418             AFS_GUNLOCK();
2419             vg = vget(AFSTOV(tvc));
2420             AFS_GLOCK();
2421             if (vg)
2422                 continue;
2423 #endif  /* AFS_OSF_ENV */
2424             break;
2425         }
2426     }
2427
2428     /* should I have a read lock on the vnode here? */
2429     if (tvc) {
2430         if (retry) *retry = 0;
2431 #if !defined(AFS_OSF_ENV)
2432         osi_vnhold(tvc, retry);  /* already held, above */
2433         if (retry && *retry) 
2434           return 0;
2435 #endif
2436         /*
2437          * only move to front of vlru if we have proper vcache locking)
2438          */
2439         if (flag & DO_VLRU) {
2440            if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2441               refpanic ("FindVC VLRU inconsistent1");
2442            }
2443            if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2444               refpanic ("FindVC VLRU inconsistent1");
2445            }
2446            if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2447               refpanic ("FindVC VLRU inconsistent2");
2448            }
2449             UpgradeSToWLock(&afs_xvcache,26);
2450             QRemove(&tvc->vlruq);
2451             QAdd(&VLRU, &tvc->vlruq);
2452             ConvertWToSLock(&afs_xvcache);
2453            if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2454               refpanic ("FindVC VLRU inconsistent1");
2455            }
2456            if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2457               refpanic ("FindVC VLRU inconsistent2");
2458            }
2459            if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2460               refpanic ("FindVC VLRU inconsistent3");
2461            }
2462         }
2463         vcachegen++;
2464     } 
2465
2466     if (flag & DO_STATS) {
2467       if (tvc)  afs_stats_cmperf.vcacheHits++;
2468       else      afs_stats_cmperf.vcacheMisses++;
2469       if (afid->Cell == LOCALCELL)
2470         afs_stats_cmperf.vlocalAccesses++;
2471       else
2472         afs_stats_cmperf.vremoteAccesses++;
2473     }
2474
2475 #ifdef AFS_LINUX22_ENV
2476     if (tvc && (tvc->states & CStatd))
2477         vcache2inode(tvc); /* mainly to reset i_nlink */
2478 #endif
2479 #ifdef AFS_DARWIN_ENV
2480     if (tvc)
2481         osi_VM_Setup(tvc);
2482 #endif
2483     return tvc;
2484 } /*afs_FindVCache*/
2485
2486 /*
2487  * afs_NFSFindVCache
2488  *
2489  * Description:
2490  *      Find a vcache entry given a fid. Does a wildcard match on what we
2491  *      have for the fid. If more than one entry, don't return anything.
2492  *
2493  * Parameters:
2494  *      avcp : Fill in pointer if we found one and only one.
2495  *      afid : Pointer to the fid whose cache entry we desire.
2496  *      retry: (SGI-specific) tell the caller to drop the lock on xvcache, 
2497  *             unlock the vnode, and try again.
2498  *      flags: bit 1 to specify whether to compute hit statistics.  Not
2499  *             set if FindVCache is called as part of internal bookkeeping.
2500  *
2501  * Environment:
2502  *      Must be called with the afs_xvcache lock at least held at
2503  *      the read level.  In order to do the VLRU adjustment, the xvcache lock
2504  *      must be shared-- we upgrade it here.
2505  *
2506  * Return value:
2507  *      number of matches found.
2508  */
2509
2510 int afs_duplicate_nfs_fids=0;
2511
2512 afs_int32 afs_NFSFindVCache(avcp, afid, lockit)
2513      struct vcache **avcp;
2514     struct VenusFid *afid;
2515     afs_int32 lockit;
2516 { /*afs_FindVCache*/
2517
2518     register struct vcache *tvc;
2519     afs_int32 i;
2520     afs_int32 retry = 0;
2521     afs_int32 count = 0;
2522     struct vcache *found_tvc = NULL;
2523
2524     AFS_STATCNT(afs_FindVCache);
2525
2526  loop:
2527
2528     ObtainSharedLock(&afs_xvcache,331); 
2529
2530     i = VCHash(afid);
2531     for(tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2532         /* Match only on what we have.... */
2533         if (((tvc->fid.Fid.Vnode & 0xffff) == afid->Fid.Vnode)
2534             && (tvc->fid.Fid.Volume == afid->Fid.Volume)
2535             && ((tvc->fid.Fid.Unique & 0xffffff) == afid->Fid.Unique)
2536             && (tvc->fid.Cell == afid->Cell)) {
2537 #ifdef  AFS_OSF_ENV
2538             /* Grab this vnode, possibly reactivating from the free list */
2539             int vg;
2540             AFS_GUNLOCK();
2541             vg = vget(AFSTOV(tvc));
2542             AFS_GLOCK();
2543             if (vg) {
2544                 /* This vnode no longer exists. */
2545                 continue;
2546             }
2547 #endif  /* AFS_OSF_ENV */
2548             count ++;
2549             if (found_tvc) {
2550                 /* Duplicates */
2551 #ifdef AFS_OSF_ENV
2552                 /* Drop our reference counts. */
2553                 vrele(AFSTOV(tvc));
2554                 vrele(AFSTOV(found_tvc));
2555 #endif
2556                 afs_duplicate_nfs_fids++;
2557                 ReleaseSharedLock(&afs_xvcache);
2558                 return count;
2559             }
2560             found_tvc = tvc;
2561         }
2562     }
2563
2564     tvc = found_tvc;
2565     /* should I have a read lock on the vnode here? */
2566     if (tvc) {
2567 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2568         osi_vnhold(tvc, &retry); 
2569         if (retry) {
2570             count = 0;
2571             found_tvc = (struct vcache*)0;
2572             ReleaseSharedLock(&afs_xvcache);
2573             spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2574             goto loop;
2575         }
2576 #else
2577 #if !defined(AFS_OSF_ENV)
2578         osi_vnhold(tvc, (int*)0);  /* already held, above */
2579 #endif
2580 #endif
2581         /*
2582          * We obtained the xvcache lock above.
2583          */
2584         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2585             refpanic ("FindVC VLRU inconsistent1");
2586         }
2587         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2588             refpanic ("FindVC VLRU inconsistent1");
2589         }
2590         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2591             refpanic ("FindVC VLRU inconsistent2");
2592         }
2593         UpgradeSToWLock(&afs_xvcache,568);
2594         QRemove(&tvc->vlruq);
2595         QAdd(&VLRU, &tvc->vlruq);
2596         ConvertWToSLock(&afs_xvcache);
2597         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2598             refpanic ("FindVC VLRU inconsistent1");
2599         }
2600         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2601             refpanic ("FindVC VLRU inconsistent2");
2602         }
2603         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2604             refpanic ("FindVC VLRU inconsistent3");
2605         }
2606     }
2607     vcachegen++;
2608
2609     if (tvc)    afs_stats_cmperf.vcacheHits++;
2610     else        afs_stats_cmperf.vcacheMisses++;
2611     if (afid->Cell == LOCALCELL)
2612         afs_stats_cmperf.vlocalAccesses++;
2613     else
2614         afs_stats_cmperf.vremoteAccesses++;
2615
2616     *avcp = tvc; /* May be null */
2617
2618     ReleaseSharedLock(&afs_xvcache);
2619     return (tvc ? 1 : 0);
2620
2621 } /*afs_NFSFindVCache*/
2622
2623
2624
2625
2626 /*
2627  * afs_vcacheInit
2628  *
2629  * Initialize vcache related variables
2630  */
2631 void afs_vcacheInit(int astatSize)
2632 {
2633     register struct vcache *tvp;
2634     int i;
2635 #if     defined(AFS_OSF_ENV)
2636     if (!afs_maxvcount) {
2637 #if     defined(AFS_OSF30_ENV)
2638         afs_maxvcount = max_vnodes/2;  /* limit ourselves to half the total */
2639 #else
2640         afs_maxvcount = nvnode/2;  /* limit ourselves to half the total */  
2641 #endif 
2642         if (astatSize < afs_maxvcount) {
2643             afs_maxvcount = astatSize;
2644         }
2645     }
2646 #else   /* AFS_OSF_ENV */
2647     freeVCList = (struct vcache *)0;
2648 #endif
2649
2650     RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2651     LOCK_INIT(&afs_xvcb, "afs_xvcb");
2652
2653 #if     !defined(AFS_OSF_ENV)
2654     /* Allocate and thread the struct vcache entries */
2655     tvp = (struct vcache *) afs_osi_Alloc(astatSize * sizeof(struct vcache));
2656     memset((char *)tvp, 0, sizeof(struct vcache)*astatSize);
2657
2658     Initial_freeVCList = tvp;
2659     freeVCList = &(tvp[0]);
2660     for(i=0; i < astatSize-1; i++) {
2661        tvp[i].nextfree = &(tvp[i+1]);
2662     }   
2663     tvp[astatSize-1].nextfree = (struct vcache *) 0;
2664 #ifdef  AFS_AIX32_ENV
2665     pin((char *)tvp, astatSize * sizeof(struct vcache));        /* XXX */    
2666 #endif
2667 #endif
2668
2669
2670 #if defined(AFS_SGI_ENV)
2671     for(i=0; i < astatSize; i++) {
2672         char name[METER_NAMSZ];
2673         struct vcache *tvc = &tvp[i];
2674
2675         tvc->v.v_number = ++afsvnumbers;
2676         tvc->vc_rwlockid = OSI_NO_LOCKID;
2677         initnsema(&tvc->vc_rwlock, 1, makesname(name, "vrw", tvc->v.v_number));
2678 #ifndef AFS_SGI53_ENV
2679         initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
2680 #endif
2681 #ifndef AFS_SGI62_ENV
2682         initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
2683 #endif /* AFS_SGI62_ENV */
2684     }
2685 #endif
2686
2687     QInit(&VLRU);
2688
2689
2690 }
2691
2692 /*
2693  * shutdown_vcache
2694  *
2695  */
2696 void shutdown_vcache(void)
2697 {
2698     int i;
2699     struct afs_cbr *tsp, *nsp;
2700     /*
2701      * XXX We may potentially miss some of the vcaches because if when there're no
2702      * free vcache entries and all the vcache entries are active ones then we allocate
2703      * an additional one - admittedly we almost never had that occur.
2704      */
2705 #if     !defined(AFS_OSF_ENV)
2706     afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2707 #endif
2708 #ifdef  AFS_AIX32_ENV
2709     unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2710 #endif
2711
2712     {
2713         register struct afs_q *tq, *uq;
2714         register struct vcache *tvc;
2715         for (tq = VLRU.prev; tq != &VLRU; tq = uq) {
2716             tvc = QTOV(tq);
2717             uq = QPrev(tq);
2718             if (tvc->mvid) {
2719                 osi_FreeSmallSpace(tvc->mvid);
2720                 tvc->mvid = (struct VenusFid*)0;
2721             }
2722 #ifdef  AFS_AIX_ENV
2723             aix_gnode_rele(AFSTOV(tvc));
2724 #endif
2725             if (tvc->linkData) {
2726                 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
2727                 tvc->linkData = 0;
2728             }
2729         }
2730         /* 
2731          * Also free the remaining ones in the Cache 
2732          */
2733         for (i=0; i < VCSIZE; i++) {
2734             for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2735                 if (tvc->mvid) {
2736                     osi_FreeSmallSpace(tvc->mvid);
2737                     tvc->mvid = (struct VenusFid*)0;
2738                 }
2739 #ifdef  AFS_AIX_ENV
2740                 if (tvc->v.v_gnode)
2741                     afs_osi_Free(tvc->v.v_gnode, sizeof(struct gnode));
2742 #ifdef  AFS_AIX32_ENV
2743                 if (tvc->segid) {
2744                     AFS_GUNLOCK();
2745                     vms_delete(tvc->segid);
2746                     AFS_GLOCK();
2747                     tvc->segid = tvc->vmh = NULL;
2748                     if (VREFCOUNT(tvc)) osi_Panic("flushVcache: vm race");
2749                 }
2750                 if (tvc->credp) {
2751                     crfree(tvc->credp);
2752                     tvc->credp = NULL;
2753                 }
2754 #endif
2755 #endif
2756 #if     defined(AFS_SUN5_ENV)
2757                 if (tvc->credp) {
2758                     crfree(tvc->credp);
2759                     tvc->credp = NULL;
2760                 }
2761 #endif
2762                 if (tvc->linkData) {
2763                     afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
2764                     tvc->linkData = 0;
2765                 }
2766
2767                 afs_FreeAllAxs(&(tvc->Access));
2768             }
2769             afs_vhashT[i] = 0;
2770         }
2771     }
2772     /*
2773      * Free any leftover callback queue
2774      */
2775     for (tsp = afs_cbrSpace; tsp; tsp = nsp ) {
2776         nsp = tsp->next;
2777         afs_osi_Free((char *)tsp, AFS_NCBRS * sizeof(struct afs_cbr));
2778     }
2779     afs_cbrSpace = 0;
2780
2781 #if     !defined(AFS_OSF_ENV)
2782     freeVCList = Initial_freeVCList = 0;
2783 #endif
2784     RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2785     LOCK_INIT(&afs_xvcb, "afs_xvcb");
2786     QInit(&VLRU);
2787
2788 }