linux-kernel-detect-gfp-mask-in-struct-address-space-20020624
[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 #ifdef STRUCT_ADDRESS_SPACE_HAS_GFP_MASK
1001         ip->i_data.gfp_mask = GFP_HIGHUSER;
1002 #endif
1003         ip->i_mapping = &ip->i_data;
1004 #ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
1005         init_rwsem(&ip->i_truncate_sem);
1006 #endif
1007 #else
1008         sema_init(&ip->i_atomic_write, 1);
1009         init_waitqueue(&ip->i_wait);
1010 #endif
1011         INIT_LIST_HEAD(&ip->i_hash);
1012         INIT_LIST_HEAD(&ip->i_dentry);
1013         if (afs_globalVFS) {
1014             ip->i_dev = afs_globalVFS->s_dev;
1015             ip->i_sb = afs_globalVFS;
1016         }
1017      }
1018 #endif
1019     tvc->h1.dchint = 0;
1020     osi_dnlc_purgedp(tvc);  /* this may be overkill */
1021     memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
1022     memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
1023     tvc->slocks = (struct SimpleLocks *)0;
1024     i = VCHash(afid);
1025
1026     tvc->hnext = afs_vhashT[i];
1027     afs_vhashT[i] = tvc;
1028     if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1029        refpanic ("NewVCache VLRU inconsistent");
1030     }
1031     QAdd(&VLRU, &tvc->vlruq);                           /* put in lruq */
1032     if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1033        refpanic ("NewVCache VLRU inconsistent2");
1034     }
1035     if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
1036        refpanic ("NewVCache VLRU inconsistent3");
1037     }
1038     if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
1039        refpanic ("NewVCache VLRU inconsistent4");
1040     }
1041     vcachegen++;
1042
1043     return tvc;
1044
1045 } /*afs_NewVCache*/
1046
1047
1048 /*
1049  * afs_FlushActiveVcaches
1050  *
1051  * Description:
1052  *      ???
1053  *
1054  * Parameters:
1055  *      doflocks : Do we handle flocks?
1056  */
1057 /* LOCK: afs_FlushActiveVcaches afs_xvcache N */
1058 void
1059 afs_FlushActiveVcaches(doflocks)
1060     register afs_int32 doflocks;
1061
1062 { /*afs_FlushActiveVcaches*/
1063
1064     register struct vcache *tvc;
1065     register int i;
1066     register struct conn *tc;
1067     register afs_int32 code;
1068     register struct AFS_UCRED *cred;
1069     struct vrequest treq, ureq;
1070     struct AFSVolSync tsync;
1071     int didCore;
1072     XSTATS_DECLS
1073
1074     AFS_STATCNT(afs_FlushActiveVcaches);
1075     ObtainReadLock(&afs_xvcache);
1076     for(i=0;i<VCSIZE;i++) {
1077         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
1078             if (doflocks && tvc->flockCount != 0) {
1079                 /* if this entry has an flock, send a keep-alive call out */
1080                 osi_vnhold(tvc, 0);
1081                 ReleaseReadLock(&afs_xvcache);
1082                 ObtainWriteLock(&tvc->lock,51);
1083                 do {
1084                     afs_InitReq(&treq, &afs_osi_cred);
1085                     treq.flags |= O_NONBLOCK;
1086
1087                     tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
1088                     if (tc) {
1089                       XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
1090                       RX_AFS_GUNLOCK();
1091                       code =
1092                             RXAFS_ExtendLock(tc->id,
1093                                              (struct AFSFid *) &tvc->fid.Fid,
1094                                              &tsync);
1095                       RX_AFS_GLOCK();
1096                       XSTATS_END_TIME;
1097                     }
1098                     else code = -1;
1099                 } while
1100                     (afs_Analyze(tc, code, &tvc->fid, &treq,
1101                                  AFS_STATS_FS_RPCIDX_EXTENDLOCK,
1102                                  SHARED_LOCK, (struct cell *)0));
1103
1104                 ReleaseWriteLock(&tvc->lock);
1105                 ObtainReadLock(&afs_xvcache);
1106                 AFS_FAST_RELE(tvc);
1107             }
1108             didCore = 0;
1109             if ((tvc->states & CCore) || (tvc->states & CUnlinkedDel)) {
1110                 /*
1111                  * Don't let it evaporate in case someone else is in
1112                  * this code.  Also, drop the afs_xvcache lock while
1113                  * getting vcache locks.
1114                  */
1115                 osi_vnhold(tvc,0);
1116                 ReleaseReadLock(&afs_xvcache);
1117 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1118                 afs_BozonLock(&tvc->pvnLock, tvc);
1119 #endif
1120 #if defined(AFS_SGI_ENV)
1121                 /*
1122                  * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
1123                  */
1124                 osi_Assert(VREFCOUNT(tvc) > 0);
1125                 AFS_RWLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1126 #endif
1127                 ObtainWriteLock(&tvc->lock,52);
1128                 if (tvc->states & CCore) {
1129                     tvc->states &= ~CCore;
1130                     /* XXXX Find better place-holder for cred XXXX */
1131                     cred = (struct AFS_UCRED *) tvc->linkData;
1132                     tvc->linkData = (char *) 0; /* XXX */
1133                     afs_InitReq(&ureq, cred);
1134                     afs_Trace2(afs_iclSetp, CM_TRACE_ACTCCORE,
1135                                ICL_TYPE_POINTER, tvc,
1136                                ICL_TYPE_INT32, tvc->execsOrWriters);
1137                     code = afs_StoreOnLastReference(tvc, &ureq);
1138                     ReleaseWriteLock(&tvc->lock);
1139 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1140                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1141 #endif
1142                     hzero(tvc->flushDV);
1143                     osi_FlushText(tvc);
1144                     didCore = 1;
1145                     if (code && code != VNOVNODE) {
1146                         afs_StoreWarn(code, tvc->fid.Fid.Volume,
1147                                       /* /dev/console */ 1);
1148                     }
1149                 } else if (tvc->states & CUnlinkedDel) {
1150                     /*
1151                      * Ignore errors 
1152                      */
1153                     ReleaseWriteLock(&tvc->lock);
1154 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) 
1155                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1156 #endif
1157 #if defined(AFS_SGI_ENV)
1158                     AFS_RWUNLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1159 #endif
1160                     afs_remunlink(tvc, 0);
1161 #if defined(AFS_SGI_ENV)
1162                     AFS_RWLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1163 #endif
1164                 }
1165                 else {
1166                     /* lost (or won, perhaps) the race condition */
1167                     ReleaseWriteLock(&tvc->lock);
1168 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)
1169                     afs_BozonUnlock(&tvc->pvnLock, tvc);
1170 #endif
1171                 }
1172 #if defined(AFS_SGI_ENV)
1173                 AFS_RWUNLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
1174 #endif
1175                 ObtainReadLock(&afs_xvcache);
1176                 AFS_FAST_RELE(tvc);
1177                 if (didCore) {
1178 #ifdef  AFS_GFS_ENV
1179                     VREFCOUNT_DEC(tvc);
1180 #else
1181                     AFS_RELE(AFSTOV(tvc));
1182 #endif
1183                     /* Matches write code setting CCore flag */
1184                     crfree(cred);
1185                 }
1186             }          
1187 #ifdef AFS_DARWIN_ENV
1188             if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
1189                 if (tvc->opens) panic("flushactive open, hasubc, but refcnt 1");
1190                 osi_VM_TryReclaim(tvc,0);
1191             }
1192 #endif
1193         }
1194     }
1195     ReleaseReadLock(&afs_xvcache);
1196
1197 } /*afs_FlushActiveVcaches*/
1198
1199
1200 /*
1201  * afs_VerifyVCache
1202  *
1203  * Description:
1204  *      Make sure a cache entry is up-to-date status-wise.
1205  * 
1206  * NOTE: everywhere that calls this can potentially be sped up
1207  *       by checking CStatd first, and avoiding doing the InitReq
1208  *       if this is up-to-date.
1209  *
1210  *  Anymore, the only places that call this KNOW already that the 
1211  *  vcache is not up-to-date, so we don't screw around.
1212  *
1213  * Parameters:
1214  *      avc  : Ptr to vcache entry to verify.
1215  *      areq : ???
1216  */
1217
1218 int afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq)
1219 {
1220     register struct vcache *tvc;
1221
1222     AFS_STATCNT(afs_VerifyVCache);
1223
1224 #if defined(AFS_OSF_ENV)
1225     ObtainReadLock(&avc->lock);
1226     if (afs_IsWired(avc)) {
1227         ReleaseReadLock(&avc->lock);
1228         return 0;
1229     }
1230     ReleaseReadLock(&avc->lock);
1231 #endif /* AFS_OSF_ENV */
1232     /* otherwise we must fetch the status info */
1233
1234     ObtainWriteLock(&avc->lock,53);
1235     if (avc->states & CStatd) {
1236         ReleaseWriteLock(&avc->lock);
1237         return 0;
1238     }
1239     ObtainWriteLock(&afs_xcbhash, 461);
1240     avc->states &= ~( CStatd | CUnique );   
1241     avc->callback = (struct server *)0;
1242     afs_DequeueCallback(avc);
1243     ReleaseWriteLock(&afs_xcbhash);
1244     ReleaseWriteLock(&avc->lock);
1245
1246     /* since we've been called back, or the callback has expired, 
1247      * it's possible that the contents of this directory, or this 
1248      * file's name have changed, thus invalidating the dnlc contents.
1249      */
1250     if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
1251       osi_dnlc_purgedp (avc);
1252     else
1253       osi_dnlc_purgevp (avc);
1254     
1255     /* fetch the status info */
1256     tvc = afs_GetVCache(&avc->fid, areq, (afs_int32*)0, avc, READ_LOCK);
1257     if (!tvc) return ENOENT;
1258     /* Put it back; caller has already incremented vrefCount */
1259     afs_PutVCache(tvc, READ_LOCK);
1260     return 0;
1261
1262 } /*afs_VerifyVCache*/
1263
1264
1265 /*
1266  * afs_SimpleVStat
1267  *
1268  * Description:
1269  *      Simple copy of stat info into cache.
1270  *
1271  * Parameters:
1272  *      avc   : Ptr to vcache entry involved.
1273  *      astat : Ptr to stat info to copy.
1274  *
1275  * Environment:
1276  *      Nothing interesting.
1277  *
1278  * Callers:  as of 1992-04-29, only called by WriteVCache
1279  */
1280 static void
1281 afs_SimpleVStat(avc, astat, areq)
1282     register struct vcache *avc;
1283     register struct AFSFetchStatus *astat;
1284     struct vrequest *areq;
1285 { /*afs_SimpleVStat*/
1286
1287     afs_size_t length;
1288     AFS_STATCNT(afs_SimpleVStat);
1289
1290 #ifdef AFS_SGI_ENV
1291     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1292         && !AFS_VN_MAPPED((vnode_t*)avc))
1293 #else
1294     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc))
1295 #endif
1296
1297         {
1298 #ifdef AFS_64BIT_ClIENT
1299             FillInt64(length, astat->Length_hi, astat->Length);
1300 #else /* AFS_64BIT_CLIENT */
1301             length = astat->Length;
1302 #endif /* AFS_64BIT_CLIENT */
1303 #if defined(AFS_SGI_ENV)
1304             osi_Assert((valusema(&avc->vc_rwlock) <= 0) &&
1305                    (OSI_GET_LOCKID() == avc->vc_rwlockid));
1306             if (length < avc->m.Length) {
1307                 vnode_t *vp = (vnode_t *)avc;
1308                 
1309                 osi_Assert(WriteLocked(&avc->lock));
1310                 ReleaseWriteLock(&avc->lock);
1311                 AFS_GUNLOCK();
1312                 PTOSSVP(vp, (off_t)length, (off_t)MAXLONG);
1313                 AFS_GLOCK();
1314                 ObtainWriteLock(&avc->lock,67);
1315             }
1316 #endif
1317             /* if writing the file, don't fetch over this value */
1318             afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT,
1319                        ICL_TYPE_POINTER, avc,
1320                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1321                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1322             avc->m.Length = length;
1323             avc->m.Date = astat->ClientModTime;
1324         }
1325     avc->m.Owner = astat->Owner;
1326     avc->m.Group = astat->Group;
1327     avc->m.Mode = astat->UnixModeBits;
1328     if (vType(avc) == VREG) {
1329         avc->m.Mode |= S_IFREG;
1330     }
1331     else if (vType(avc) == VDIR) {
1332         avc->m.Mode |= S_IFDIR;
1333     }
1334     else if (vType(avc) == VLNK) {
1335
1336
1337
1338         avc->m.Mode |= S_IFLNK;
1339         if ((avc->m.Mode & 0111) == 0) avc->mvstat = 1;
1340     }
1341     if (avc->states & CForeign) {
1342       struct axscache *ac;
1343         avc->anyAccess = astat->AnonymousAccess;
1344 #ifdef badidea
1345         if ((astat->CallerAccess & ~astat->AnonymousAccess)) 
1346          /*   USED TO SAY : 
1347           * Caller has at least one bit not covered by anonymous, and
1348           * thus may have interesting rights.
1349           *
1350           * HOWEVER, this is a really bad idea, because any access query
1351           * for bits which aren't covered by anonymous, on behalf of a user
1352           * who doesn't have any special rights, will result in an answer of 
1353           * the form "I don't know, lets make a FetchStatus RPC and find out!"
1354           * It's an especially bad idea under Ultrix, since (due to the lack of
1355           * a proper access() call) it must perform several afs_access() calls 
1356           * in order to create magic mode bits that vary according to who makes
1357           * the call.  In other words, _every_ stat() generates a test for 
1358           * writeability...
1359           */
1360 #endif /* badidea */
1361           if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1362             ac->axess =  astat->CallerAccess;
1363           else  /* not found, add a new one if possible */
1364             afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1365     }
1366
1367
1368 } /*afs_SimpleVStat*/
1369
1370
1371 /*
1372  * afs_WriteVCache
1373  *
1374  * Description:
1375  *      Store the status info *only* back to the server for a
1376  *      fid/vrequest.
1377  *
1378  * Parameters:
1379  *      avc     : Ptr to the vcache entry.
1380  *      astatus : Ptr to the status info to store.
1381  *      areq    : Ptr to the associated vrequest.
1382  *
1383  * Environment:
1384  *      Must be called with a shared lock held on the vnode.
1385  */
1386
1387 afs_WriteVCache(avc, astatus, areq)
1388     register struct vcache *avc;
1389     register struct AFSStoreStatus *astatus;
1390     struct vrequest *areq;
1391
1392 { /*afs_WriteVCache*/
1393   afs_int32 code;
1394   struct conn *tc;
1395     struct AFSFetchStatus OutStatus;
1396     struct AFSVolSync tsync;
1397     XSTATS_DECLS
1398
1399     AFS_STATCNT(afs_WriteVCache);
1400     afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
1401                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
1402
1403     do {
1404         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1405         if (tc) {
1406           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
1407           RX_AFS_GUNLOCK();
1408           code = RXAFS_StoreStatus(tc->id,
1409                                    (struct AFSFid *) &avc->fid.Fid,
1410                                    astatus, &OutStatus, &tsync);
1411           RX_AFS_GLOCK();
1412           XSTATS_END_TIME;
1413         }
1414         else code = -1;
1415     } while
1416         (afs_Analyze(tc, code, &avc->fid, areq,
1417                      AFS_STATS_FS_RPCIDX_STORESTATUS,
1418                      SHARED_LOCK, (struct cell *)0));
1419
1420     UpgradeSToWLock(&avc->lock,20);
1421     if (code == 0) {
1422         /* success, do the changes locally */
1423         afs_SimpleVStat(avc, &OutStatus, areq);
1424         /*
1425          * Update the date, too.  SimpleVStat didn't do this, since
1426          * it thought we were doing this after fetching new status
1427          * over a file being written.
1428          */
1429         avc->m.Date = OutStatus.ClientModTime;
1430     }
1431     else {
1432         /* failure, set up to check with server next time */
1433         ObtainWriteLock(&afs_xcbhash, 462);
1434         afs_DequeueCallback(avc);
1435         avc->states &= ~( CStatd | CUnique);  /* turn off stat valid flag */
1436         ReleaseWriteLock(&afs_xcbhash);
1437         if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
1438           osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
1439     }
1440     ConvertWToSLock(&avc->lock);
1441     return code;
1442
1443 } /*afs_WriteVCache*/
1444
1445 /*
1446  * afs_ProcessFS
1447  *
1448  * Description:
1449  *      Copy astat block into vcache info
1450  *
1451  * Parameters:
1452  *      avc   : Ptr to vcache entry.
1453  *      astat : Ptr to stat block to copy in.
1454  *      areq  : Ptr to associated request.
1455  *
1456  * Environment:
1457  *      Must be called under a write lock
1458  *
1459  * Note: this code may get dataversion and length out of sync if the file has
1460  *       been modified.  This is less than ideal.  I haven't thought about
1461  *       it sufficiently to be certain that it is adequate.
1462  */
1463 void
1464 afs_ProcessFS(avc, astat, areq)
1465     register struct vcache *avc;
1466     struct vrequest *areq;
1467     register struct AFSFetchStatus *astat;
1468
1469 { /*afs_ProcessFS*/
1470
1471     register int i;
1472     afs_size_t length;
1473     AFS_STATCNT(afs_ProcessFS);
1474
1475 #ifdef AFS_64BIT_CLIENT
1476     FillInt64(length, astat->Length_hi, astat->Length);
1477 #else /* AFS_64BIT_CLIENT */
1478     length = astat->Length;
1479 #endif /* AFS_64BIT_CLIENT */
1480     /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
1481      * number for each bulk status request. Under no circumstances
1482      * should afs_DoBulkStat store a sequence number if the new
1483      * length will be ignored when afs_ProcessFS is called with
1484      * new stats. If you change the following conditional then you
1485      * also need to change the conditional in afs_DoBulkStat.  */
1486 #ifdef AFS_SGI_ENV
1487     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc)
1488         && !AFS_VN_MAPPED((vnode_t*)avc))
1489 #else
1490     if ((avc->execsOrWriters <= 0) && !afs_DirtyPages(avc))
1491 #endif
1492         {
1493             /* if we're writing or mapping this file, don't fetch over these
1494              *  values.
1495              */
1496             afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
1497                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
1498                        ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
1499             avc->m.Length = length;
1500             avc->m.Date = astat->ClientModTime;
1501         }
1502     hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
1503     avc->m.Owner = astat->Owner;
1504     avc->m.Mode = astat->UnixModeBits;
1505     avc->m.Group = astat->Group;
1506     avc->m.LinkCount = astat->LinkCount;
1507     if (astat->FileType == File) {
1508         vSetType(avc, VREG);
1509         avc->m.Mode |= S_IFREG;
1510     }
1511     else if (astat->FileType == Directory) {
1512         vSetType(avc, VDIR);
1513         avc->m.Mode |= S_IFDIR;
1514     }
1515     else if (astat->FileType == SymbolicLink) {
1516         if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
1517             vSetType(avc, VDIR);
1518             avc->m.Mode |= S_IFDIR;
1519         } else {
1520             vSetType(avc, VLNK);
1521             avc->m.Mode |= S_IFLNK;
1522         }
1523         if ((avc->m.Mode & 0111) == 0) {
1524             avc->mvstat = 1;
1525         }
1526     }
1527     avc->anyAccess = astat->AnonymousAccess;
1528 #ifdef badidea
1529     if ((astat->CallerAccess & ~astat->AnonymousAccess)) 
1530       /*   USED TO SAY : 
1531        * Caller has at least one bit not covered by anonymous, and
1532        * thus may have interesting rights.
1533        *
1534        * HOWEVER, this is a really bad idea, because any access query
1535        * for bits which aren't covered by anonymous, on behalf of a user
1536        * who doesn't have any special rights, will result in an answer of 
1537        * the form "I don't know, lets make a FetchStatus RPC and find out!"
1538        * It's an especially bad idea under Ultrix, since (due to the lack of
1539        * a proper access() call) it must perform several afs_access() calls 
1540        * in order to create magic mode bits that vary according to who makes
1541        * the call.  In other words, _every_ stat() generates a test for 
1542        * writeability...
1543        */
1544 #endif /* badidea */
1545       {
1546         struct axscache *ac;
1547         if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
1548           ac->axess =  astat->CallerAccess;
1549         else  /* not found, add a new one if possible */
1550           afs_AddAxs(avc->Access, areq->uid, astat->CallerAccess);
1551       }
1552
1553 #ifdef AFS_LINUX22_ENV
1554     vcache2inode(avc);    /* Set the inode attr cache */
1555 #endif
1556
1557 } /*afs_ProcessFS*/
1558
1559
1560 afs_RemoteLookup(afid, areq, name, nfid, OutStatusp, CallBackp, serverp, tsyncp)
1561     register struct VenusFid *afid;
1562     struct vrequest *areq;
1563     char *name;
1564     struct VenusFid *nfid;
1565     struct AFSFetchStatus *OutStatusp;
1566     struct AFSCallBack *CallBackp;
1567     struct server **serverp;
1568     struct AFSVolSync *tsyncp;
1569 {
1570     afs_int32 code, i;
1571     register struct vcache *tvc;
1572     struct volume *tvp;
1573     afs_uint32 start;
1574     register struct conn *tc;
1575     struct AFSFetchStatus OutDirStatus;
1576     XSTATS_DECLS
1577
1578     if (!name) name = "";       /* XXX */
1579     do {
1580         tc = afs_Conn(afid, areq, SHARED_LOCK);
1581         if (tc) {
1582             if (serverp) *serverp = tc->srvr->server;
1583             start = osi_Time();
1584             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
1585             RX_AFS_GUNLOCK();
1586             code = RXAFS_Lookup(tc->id, (struct AFSFid *) &afid->Fid, name,
1587                                 (struct AFSFid *) &nfid->Fid, 
1588                                 OutStatusp, &OutDirStatus, CallBackp, tsyncp);
1589             RX_AFS_GLOCK();
1590             XSTATS_END_TIME;
1591         } else 
1592             code = -1;
1593     } while
1594         (afs_Analyze(tc, code, afid, areq,
1595                      AFS_STATS_FS_RPCIDX_XLOOKUP,
1596                      SHARED_LOCK, (struct cell *)0));
1597
1598     return code;
1599 }
1600
1601
1602 /*
1603  * afs_GetVCache
1604  *
1605  * Description:
1606  *      Given a file id and a vrequest structure, fetch the status
1607  *      information associated with the file.
1608  *
1609  * Parameters:
1610  *      afid : File ID.
1611  *      areq : Ptr to associated vrequest structure, specifying the
1612  *              user whose authentication tokens will be used.
1613  *      avc  : caller may already have a vcache for this file, which is 
1614  *             already held.
1615  *
1616  * Environment:
1617  *      The cache entry is returned with an increased vrefCount field.
1618  *      The entry must be discarded by calling afs_PutVCache when you
1619  *      are through using the pointer to the cache entry.
1620  *
1621  *      You should not hold any locks when calling this function, except
1622  *      locks on other vcache entries.  If you lock more than one vcache
1623  *      entry simultaneously, you should lock them in this order:
1624  *
1625  *          1. Lock all files first, then directories.
1626  *          2.  Within a particular type, lock entries in Fid.Vnode order.
1627  *  
1628  *      This locking hierarchy is convenient because it allows locking
1629  *      of a parent dir cache entry, given a file (to check its access
1630  *      control list).  It also allows renames to be handled easily by
1631  *      locking directories in a constant order.
1632  * NB.  NewVCache -> FlushVCache presently (4/10/95) drops the xvcache lock.
1633  */
1634 struct vcache *afs_GetVCache(afid, areq, cached, avc, locktype)
1635     register struct VenusFid *afid;
1636     struct vrequest *areq;
1637     afs_int32 *cached;
1638     afs_int32 locktype;
1639     struct vcache *avc; /* might have a vcache structure already, which must
1640                          * already be held by the caller */
1641 { /*afs_GetVCache*/
1642
1643     afs_int32 code, i, newvcache=0;
1644     register struct vcache *tvc;
1645     struct volume *tvp;
1646     afs_int32 retry;
1647
1648     AFS_STATCNT(afs_GetVCache);
1649
1650     if (cached) *cached = 0;            /* Init just in case */
1651
1652 loop:
1653     ObtainSharedLock(&afs_xvcache,5); 
1654
1655     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_STATS | DO_VLRU );
1656     if (tvc && retry) {
1657 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1658         ReleaseSharedLock(&afs_xvcache);
1659         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1660         goto loop;
1661 #endif
1662    }
1663    
1664     if (tvc) {
1665       if (cached) 
1666         *cached = 1;
1667       if (tvc->states & CStatd) {               
1668         ReleaseSharedLock(&afs_xvcache);
1669         return tvc;
1670       }
1671     }
1672     else {      
1673         UpgradeSToWLock(&afs_xvcache,21);
1674
1675         /* no cache entry, better grab one */
1676         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
1677         newvcache = 1;
1678
1679         ConvertWToSLock(&afs_xvcache);
1680         afs_stats_cmperf.vcacheMisses++;
1681     }
1682
1683     ReleaseSharedLock(&afs_xvcache);
1684
1685     ObtainWriteLock(&tvc->lock,54);
1686
1687     if (tvc->states & CStatd) {
1688 #ifdef AFS_LINUX22_ENV
1689         vcache2inode(tvc);
1690 #endif
1691         ReleaseWriteLock(&tvc->lock);
1692 #ifdef AFS_DARWIN_ENV
1693         osi_VM_Setup(tvc);
1694 #endif
1695         return tvc;
1696     }
1697
1698 #if defined(AFS_OSF_ENV)
1699       if (afs_IsWired(tvc)) {
1700           ReleaseWriteLock(&tvc->lock);
1701           return tvc;
1702       }
1703 #endif /* AFS_OSF_ENV */
1704
1705     ObtainWriteLock(&afs_xcbhash, 464);
1706     tvc->states &= ~CUnique;   
1707     tvc->callback = 0;
1708     afs_DequeueCallback(tvc);
1709     ReleaseWriteLock(&afs_xcbhash);
1710
1711     /* It is always appropriate to throw away all the access rights? */
1712     afs_FreeAllAxs(&(tvc->Access));
1713     tvp = afs_GetVolume(afid, areq, READ_LOCK);   /* copy useful per-volume info */
1714     if (tvp) {
1715         if ((tvp->states & VForeign)) {
1716             if (newvcache) tvc->states |= CForeign;
1717             if (newvcache && (tvp->rootVnode == afid->Fid.Vnode) 
1718                 && (tvp->rootUnique == afid->Fid.Unique)) {
1719                 tvc->mvstat = 2;
1720               }
1721         }
1722         if (tvp->states & VRO) tvc->states |= CRO;
1723         if (tvp->states & VBackup) tvc->states |= CBackup;
1724         /* now copy ".." entry back out of volume structure, if necessary */
1725         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
1726             if (!tvc->mvid)
1727                 tvc->mvid = (struct VenusFid *)
1728                     osi_AllocSmallSpace(sizeof(struct VenusFid));
1729             *tvc->mvid = tvp->dotdot;
1730         }
1731         afs_PutVolume(tvp, READ_LOCK);
1732     }
1733
1734     /* stat the file */
1735     afs_RemoveVCB(afid);
1736     {
1737         struct AFSFetchStatus OutStatus;
1738
1739         if (afs_DynrootNewVnode(tvc, &OutStatus)) {
1740             afs_ProcessFS(tvc, &OutStatus, areq);
1741             tvc->states |= CStatd | CUnique;
1742             code = 0;
1743         } else {
1744             code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
1745         }
1746     }
1747
1748     if (code) {
1749         ReleaseWriteLock(&tvc->lock);
1750
1751         ObtainReadLock(&afs_xvcache);
1752         AFS_FAST_RELE(tvc);
1753         ReleaseReadLock(&afs_xvcache);
1754         return (struct vcache *) 0;
1755     }
1756
1757     ReleaseWriteLock(&tvc->lock);
1758 #ifdef AFS_DARWIN_ENV
1759     osi_VM_Setup(avc);
1760 #endif
1761     return tvc;
1762
1763 } /*afs_GetVCache*/
1764
1765
1766
1767 struct vcache *afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq,
1768                                 afs_int32 *cached, afs_int32 locktype,
1769                                 struct vcache *adp, char *aname)
1770 {
1771     afs_int32 code, now, newvcache=0, hash;
1772     struct VenusFid nfid;
1773     register struct vcache *tvc;
1774     struct volume *tvp;
1775     struct AFSFetchStatus OutStatus;
1776     struct AFSCallBack CallBack;
1777     struct AFSVolSync tsync;
1778     struct server *serverp = 0;
1779     afs_int32 origCBs;
1780     afs_int32 retry;
1781
1782     AFS_STATCNT(afs_GetVCache);
1783     if (cached) *cached = 0;            /* Init just in case */
1784
1785   loop1:
1786     ObtainReadLock(&afs_xvcache);
1787     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_STATS /* no vlru */);
1788
1789     if (tvc) {
1790       ReleaseReadLock(&afs_xvcache);
1791       if (retry) {
1792 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1793         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1794         goto loop1;
1795 #endif
1796       }
1797       ObtainReadLock(&tvc->lock);
1798
1799       if (tvc->states & CStatd) {
1800         if (cached) {
1801           *cached = 1;
1802         }
1803         ReleaseReadLock(&tvc->lock);
1804         return tvc;
1805       } 
1806       tvc->states &= ~CUnique;   
1807
1808         ReleaseReadLock(&tvc->lock);
1809         ObtainReadLock(&afs_xvcache);
1810         AFS_FAST_RELE(tvc);
1811     }  /* if (tvc) */
1812
1813     ReleaseReadLock(&afs_xvcache);
1814
1815     /* lookup the file */
1816     nfid = *afid;
1817     now = osi_Time();
1818     origCBs = afs_allCBs;       /* if anything changes, we don't have a cb */
1819     code = afs_RemoteLookup(&adp->fid, areq, aname, &nfid, &OutStatus, &CallBack,
1820                             &serverp, &tsync);  
1821
1822   loop2:
1823     ObtainSharedLock(&afs_xvcache,6);
1824     tvc = afs_FindVCache(&nfid, 0, 0, &retry, DO_VLRU /* no xstats now*/);
1825     if (tvc && retry) {
1826 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
1827       ReleaseSharedLock(&afs_xvcache);
1828       spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
1829       goto loop2;
1830 #endif
1831     }
1832
1833     if (!tvc) {
1834         /* no cache entry, better grab one */
1835         UpgradeSToWLock(&afs_xvcache,22);
1836         tvc = afs_NewVCache(&nfid, (struct server *)0, 1, WRITE_LOCK);
1837         newvcache = 1;
1838         ConvertWToSLock(&afs_xvcache);
1839     }
1840
1841     ReleaseSharedLock(&afs_xvcache);
1842     ObtainWriteLock(&tvc->lock,55);
1843  
1844     /* It is always appropriate to throw away all the access rights? */
1845     afs_FreeAllAxs(&(tvc->Access));
1846     tvp = afs_GetVolume(afid, areq, READ_LOCK); /* copy useful per-vol info */
1847     if (tvp) {
1848         if ((tvp->states & VForeign)) {
1849             if (newvcache) tvc->states |= CForeign;
1850             if (newvcache && (tvp->rootVnode == afid->Fid.Vnode)
1851                 && (tvp->rootUnique == afid->Fid.Unique))
1852                 tvc->mvstat = 2;
1853         }
1854         if (tvp->states & VRO) tvc->states |= CRO;
1855         if (tvp->states & VBackup) tvc->states |= CBackup;
1856         /* now copy ".." entry back out of volume structure, if necessary */
1857         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
1858             if (!tvc->mvid)
1859                 tvc->mvid = (struct VenusFid *)
1860                     osi_AllocSmallSpace(sizeof(struct VenusFid));
1861             *tvc->mvid = tvp->dotdot;
1862         }
1863     }
1864
1865     if (code) {
1866         ObtainWriteLock(&afs_xcbhash, 465);
1867         afs_DequeueCallback(tvc);
1868         tvc->states &= ~( CStatd | CUnique );
1869         ReleaseWriteLock(&afs_xcbhash);
1870         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1871           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1872         if ( tvp )
1873                 afs_PutVolume(tvp, READ_LOCK);
1874         ReleaseWriteLock(&tvc->lock);
1875         ObtainReadLock(&afs_xvcache);
1876         AFS_FAST_RELE(tvc);
1877         ReleaseReadLock(&afs_xvcache);
1878         return (struct vcache *) 0;
1879     }
1880
1881     ObtainWriteLock(&afs_xcbhash, 466);
1882     if (origCBs == afs_allCBs) {
1883         if (CallBack.ExpirationTime) {
1884             tvc->callback = serverp;
1885             tvc->cbExpires = CallBack.ExpirationTime+now;
1886             tvc->states |= CStatd | CUnique;
1887             tvc->states &= ~CBulkFetching;
1888             afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvp);
1889         } else if (tvc->states & CRO) {
1890             /* adapt gives us an hour. */
1891             tvc->cbExpires = 3600+osi_Time(); /*XXX*/
1892             tvc->states |= CStatd | CUnique;
1893             tvc->states &= ~CBulkFetching;
1894             afs_QueueCallback(tvc, CBHash(3600), tvp); 
1895         } else {
1896             tvc->callback = (struct server *)0;
1897             afs_DequeueCallback(tvc);
1898             tvc->states &= ~(CStatd | CUnique);   
1899             if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1900               osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1901         }
1902     } else {
1903         afs_DequeueCallback(tvc);
1904         tvc->states &= ~CStatd; 
1905         tvc->states &= ~CUnique;   
1906         tvc->callback = (struct server *)0;
1907         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
1908           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
1909     }   
1910     ReleaseWriteLock(&afs_xcbhash);
1911     if ( tvp )
1912         afs_PutVolume(tvp, READ_LOCK);
1913     afs_ProcessFS(tvc, &OutStatus, areq);
1914
1915     ReleaseWriteLock(&tvc->lock);
1916 #ifdef AFS_DARWIN_ENV
1917     osi_VM_Setup(tvc);
1918 #endif
1919     return tvc;
1920
1921 }
1922
1923 struct vcache *afs_GetRootVCache(struct VenusFid *afid,
1924                                  struct vrequest *areq, afs_int32 *cached,
1925                                  struct volume *tvolp, afs_int32 locktype)
1926 {
1927     afs_int32 code, i, newvcache = 0, haveStatus = 0;
1928     afs_int32 getNewFid = 0;
1929     afs_uint32 start;
1930     struct VenusFid nfid;
1931     register struct vcache *tvc;
1932     struct server *serverp = 0;
1933     struct AFSFetchStatus OutStatus;
1934     struct AFSCallBack CallBack;
1935     struct AFSVolSync tsync;
1936     int origCBs;
1937
1938     start = osi_Time();
1939
1940  newmtpt:
1941     if (!tvolp->rootVnode || getNewFid) {
1942         struct VenusFid tfid;
1943
1944         tfid = *afid;
1945         tfid.Fid.Vnode = 0;     /* Means get rootfid of volume */
1946         origCBs = afs_allCBs; /* ignore InitCallBackState */
1947         code = afs_RemoteLookup(&tfid, areq, (char *)0, &nfid, 
1948                                 &OutStatus, &CallBack, &serverp, &tsync);
1949         if (code) {
1950             return (struct vcache *)0;
1951         }
1952 /*      ReleaseReadLock(&tvolp->lock);           */
1953         ObtainWriteLock(&tvolp->lock,56);
1954         tvolp->rootVnode = afid->Fid.Vnode = nfid.Fid.Vnode;
1955         tvolp->rootUnique = afid->Fid.Unique = nfid.Fid.Unique;
1956         ReleaseWriteLock(&tvolp->lock); 
1957 /*      ObtainReadLock(&tvolp->lock);*/
1958         haveStatus = 1;
1959     } else {
1960         afid->Fid.Vnode = tvolp->rootVnode;
1961         afid->Fid.Unique = tvolp->rootUnique;
1962     }   
1963     
1964     ObtainSharedLock(&afs_xvcache,7);
1965     i = VCHash(afid);
1966     for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1967         if (!FidCmp(&(tvc->fid), afid)) {
1968 #ifdef  AFS_OSF_ENV
1969             /* Grab this vnode, possibly reactivating from the free list */
1970             /* for the present (95.05.25) everything on the hash table is 
1971              * definitively NOT in the free list -- at least until afs_reclaim
1972              * can be safely implemented */
1973             int vg;
1974             AFS_GUNLOCK();
1975             vg = vget(AFSTOV(tvc));   /* this bumps ref count */
1976             AFS_GLOCK();
1977             if (vg)
1978                 continue;
1979 #endif  /* AFS_OSF_ENV */
1980             break;
1981         }
1982     }
1983
1984     if (!haveStatus && (!tvc || !(tvc->states & CStatd))) {
1985         /* Mount point no longer stat'd or unknown. FID may have changed. */
1986 #ifdef AFS_OSF_ENV
1987         if (tvc)
1988             AFS_RELE(tvc);
1989 #endif
1990         tvc = (struct vcache*)0;
1991         getNewFid = 1;
1992         ReleaseSharedLock(&afs_xvcache);
1993         goto newmtpt;
1994     }
1995
1996     if (!tvc) {
1997         UpgradeSToWLock(&afs_xvcache,23);
1998         /* no cache entry, better grab one */
1999         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
2000         newvcache = 1;
2001         afs_stats_cmperf.vcacheMisses++;
2002     }
2003     else {
2004         if (cached) *cached = 1;
2005         afs_stats_cmperf.vcacheHits++;
2006 #ifdef  AFS_OSF_ENV
2007         /* we already bumped the ref count in the for loop above */
2008 #else   /* AFS_OSF_ENV */
2009         osi_vnhold(tvc,0);
2010 #endif
2011         UpgradeSToWLock(&afs_xvcache,24);
2012         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2013            refpanic ("GRVC VLRU inconsistent0");
2014         }
2015         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2016            refpanic ("GRVC VLRU inconsistent1");
2017         }
2018         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2019            refpanic ("GRVC VLRU inconsistent2");
2020         }
2021         QRemove(&tvc->vlruq);           /* move to lruq head */
2022         QAdd(&VLRU, &tvc->vlruq);
2023         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2024            refpanic ("GRVC VLRU inconsistent3");
2025         }
2026         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2027            refpanic ("GRVC VLRU inconsistent4");
2028         }
2029         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2030            refpanic ("GRVC VLRU inconsistent5");
2031         }
2032         vcachegen++;
2033     }
2034
2035     ReleaseWriteLock(&afs_xvcache);
2036
2037     if (tvc->states & CStatd) {
2038         return tvc;
2039     } else {  
2040
2041       ObtainReadLock(&tvc->lock);
2042       tvc->states &= ~CUnique;   
2043       tvc->callback = (struct server *)0;              /* redundant, perhaps */
2044       ReleaseReadLock(&tvc->lock);
2045     }
2046
2047     ObtainWriteLock(&tvc->lock,57);
2048
2049     /* It is always appropriate to throw away all the access rights? */
2050     afs_FreeAllAxs(&(tvc->Access));
2051
2052     if (newvcache) tvc->states |= CForeign;
2053     if (tvolp->states & VRO) tvc->states |= CRO;
2054     if (tvolp->states & VBackup) tvc->states |= CBackup;
2055     /* now copy ".." entry back out of volume structure, if necessary */
2056     if (newvcache && (tvolp->rootVnode == afid->Fid.Vnode) 
2057         && (tvolp->rootUnique == afid->Fid.Unique)) {
2058         tvc->mvstat = 2;
2059     }
2060     if (tvc->mvstat == 2  && tvolp->dotdot.Fid.Volume != 0) {
2061         if (!tvc->mvid)
2062             tvc->mvid = (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
2063         *tvc->mvid = tvolp->dotdot;
2064     }
2065
2066     /* stat the file */
2067     afs_RemoveVCB(afid);
2068
2069     if (!haveStatus) {
2070         struct VenusFid tfid;
2071
2072         tfid = *afid;
2073         tfid.Fid.Vnode = 0;     /* Means get rootfid of volume */
2074         origCBs = afs_allCBs; /* ignore InitCallBackState */
2075         code = afs_RemoteLookup(&tfid, areq, (char *)0, &nfid, &OutStatus,
2076                                 &CallBack, &serverp, &tsync);
2077     }
2078
2079     if (code) {
2080         ObtainWriteLock(&afs_xcbhash, 467);
2081         afs_DequeueCallback(tvc);
2082         tvc->callback = (struct server *)0;
2083         tvc->states &= ~(CStatd|CUnique);  
2084         ReleaseWriteLock(&afs_xcbhash);
2085         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2086           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2087         ReleaseWriteLock(&tvc->lock);
2088         ObtainReadLock(&afs_xvcache);
2089         AFS_FAST_RELE(tvc);
2090         ReleaseReadLock(&afs_xvcache);
2091         return (struct vcache *) 0;
2092     }
2093         
2094     ObtainWriteLock(&afs_xcbhash, 468);
2095     if (origCBs == afs_allCBs) {
2096         tvc->states |= CTruth;
2097         tvc->callback = serverp;
2098         if (CallBack.ExpirationTime != 0) {  
2099             tvc->cbExpires = CallBack.ExpirationTime+start;
2100             tvc->states |= CStatd;
2101             tvc->states &= ~CBulkFetching;
2102             afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), tvolp);
2103         } else if (tvc->states & CRO) {
2104             /* adapt gives us an hour. */
2105             tvc->cbExpires = 3600+osi_Time(); /*XXX*/
2106             tvc->states |= CStatd;
2107             tvc->states &= ~CBulkFetching;
2108             afs_QueueCallback(tvc, CBHash(3600), tvolp);
2109         }
2110     } else {
2111         afs_DequeueCallback(tvc);
2112         tvc->callback = (struct server *)0;
2113         tvc->states &= ~(CStatd | CUnique);
2114         if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2115           osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2116     }
2117     ReleaseWriteLock(&afs_xcbhash);
2118     afs_ProcessFS(tvc, &OutStatus, areq);
2119     
2120     ReleaseWriteLock(&tvc->lock);
2121     return tvc;
2122 }
2123
2124
2125
2126 /*
2127  * must be called with avc write-locked 
2128  * don't absolutely have to invalidate the hint unless the dv has 
2129  * changed, but be sure to get it right else there will be consistency bugs.
2130  */
2131 afs_int32 afs_FetchStatus(struct vcache *avc, struct VenusFid *afid,
2132                       struct vrequest *areq, struct AFSFetchStatus *Outsp)
2133 {
2134   int code;
2135   afs_uint32 start;
2136   register struct conn *tc;
2137   struct AFSCallBack CallBack;
2138   struct AFSVolSync tsync;
2139   struct volume*    volp;
2140   XSTATS_DECLS
2141
2142     do {
2143         tc = afs_Conn(afid, areq, SHARED_LOCK);
2144         avc->quick.stamp = 0; avc->h1.dchint = NULL; /* invalidate hints */
2145         if (tc) {
2146             avc->callback = tc->srvr->server;
2147             start = osi_Time();
2148             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
2149             RX_AFS_GUNLOCK();
2150             code = RXAFS_FetchStatus(tc->id,
2151                                      (struct AFSFid *) &afid->Fid,
2152                                      Outsp, &CallBack, &tsync);
2153             RX_AFS_GLOCK();
2154
2155             XSTATS_END_TIME;
2156
2157         }
2158         else code = -1;
2159     } while
2160         (afs_Analyze(tc, code, afid, areq,
2161                      AFS_STATS_FS_RPCIDX_FETCHSTATUS,
2162                      SHARED_LOCK, (struct cell *)0));
2163
2164 if (!code) {
2165   afs_ProcessFS(avc, Outsp, areq);
2166   volp = afs_GetVolume(afid, areq, READ_LOCK);
2167   ObtainWriteLock(&afs_xcbhash, 469);
2168   avc->states |= CTruth;
2169   if (avc->callback /* check for race */) {
2170     if (CallBack.ExpirationTime != 0) {  
2171       avc->cbExpires = CallBack.ExpirationTime+start;
2172       avc->states |= CStatd;
2173       avc->states &= ~CBulkFetching;
2174       afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
2175     }
2176     else if (avc->states & CRO) 
2177       { /* ordinary callback on a read-only volume -- AFS 3.2 style */
2178         avc->cbExpires = 3600+start;
2179         avc->states |= CStatd;
2180         avc->states &= ~CBulkFetching;
2181         afs_QueueCallback(avc, CBHash(3600), volp);
2182        }
2183     else {
2184       afs_DequeueCallback(avc);
2185       avc->callback = (struct server *)0;
2186       avc->states &= ~(CStatd|CUnique);  
2187       if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
2188         osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
2189     }
2190   }
2191   else {
2192     afs_DequeueCallback(avc);
2193     avc->callback = (struct server *)0;
2194     avc->states &= ~(CStatd|CUnique);  
2195     if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1)) 
2196       osi_dnlc_purgedp (avc);  /* if it (could be) a directory */
2197   }
2198   ReleaseWriteLock(&afs_xcbhash);
2199   if ( volp )
2200     afs_PutVolume(volp, READ_LOCK);
2201 }
2202 else {     /* used to undo the local callback, but that's too extreme. 
2203             * There are plenty of good reasons that fetchstatus might return 
2204             * an error, such as EPERM.  If we have the vnode cached, statd, 
2205             * with callback, might as well keep track of the fact that we 
2206             * don't have access...
2207             */
2208      if (code == EPERM || code == EACCES) {
2209        struct axscache *ac;
2210        if (avc->Access && (ac = afs_FindAxs(avc->Access, areq->uid)))
2211          ac->axess = 0;
2212        else  /* not found, add a new one if possible */
2213          afs_AddAxs(avc->Access, areq->uid, 0);
2214      }
2215 }
2216 return code;
2217 }
2218
2219 #if 0
2220 /*
2221  * afs_StuffVcache
2222  *
2223  * Description:
2224  *      Stuff some information into the vcache for the given file.
2225  *
2226  * Parameters:
2227  *      afid      : File in question.
2228  *      OutStatus : Fetch status on the file.
2229  *      CallBack  : Callback info.
2230  *      tc        : RPC connection involved.
2231  *      areq      : vrequest involved.
2232  *
2233  * Environment:
2234  *      Nothing interesting.
2235  */
2236 void
2237 afs_StuffVcache(afid, OutStatus, CallBack, tc, areq)
2238     register struct VenusFid *afid;
2239     struct AFSFetchStatus *OutStatus;
2240     struct AFSCallBack *CallBack;
2241     register struct conn *tc;
2242     struct vrequest *areq;
2243
2244 { /*afs_StuffVcache*/
2245
2246     register afs_int32 code, i, newvcache=0;
2247     register struct vcache *tvc;
2248     struct AFSVolSync tsync;
2249     struct volume *tvp;
2250     struct axscache *ac;
2251     afs_int32 retry;
2252
2253     AFS_STATCNT(afs_StuffVcache);
2254 #ifdef IFS_VCACHECOUNT
2255     ifs_gvcachecall++;
2256 #endif
2257
2258   loop:
2259     ObtainSharedLock(&afs_xvcache,8);
2260
2261     tvc = afs_FindVCache(afid, 0, 0, &retry, DO_VLRU /* no stats */);
2262     if (tvc && retry) {
2263 #if     defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2264         ReleaseSharedLock(&afs_xvcache);
2265         spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2266         goto loop;
2267 #endif
2268    }
2269
2270     if (!tvc) {
2271         /* no cache entry, better grab one */
2272         UpgradeSToWLock(&afs_xvcache,25);
2273         tvc = afs_NewVCache(afid, (struct server *)0, 1, WRITE_LOCK);
2274         newvcache = 1;
2275         ConvertWToSLock(&afs_xvcache);
2276     }
2277
2278     ReleaseSharedLock(&afs_xvcache);
2279     ObtainWriteLock(&tvc->lock,58);
2280
2281     tvc->states &= ~CStatd;
2282     if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2283       osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2284
2285     /* Is it always appropriate to throw away all the access rights? */
2286     afs_FreeAllAxs(&(tvc->Access));
2287
2288     /*Copy useful per-volume info*/
2289     tvp = afs_GetVolume(afid, areq, READ_LOCK);
2290     if (tvp) {
2291         if (newvcache && (tvp->states & VForeign)) tvc->states |= CForeign;
2292         if (tvp->states & VRO) tvc->states |= CRO;
2293         if (tvp->states & VBackup) tvc->states |= CBackup;
2294         /*
2295          * Now, copy ".." entry back out of volume structure, if
2296          * necessary
2297          */
2298         if (tvc->mvstat == 2  && tvp->dotdot.Fid.Volume != 0) {
2299             if (!tvc->mvid) tvc->mvid =
2300                 (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
2301             *tvc->mvid = tvp->dotdot;
2302         }
2303     }
2304     /* store the stat on the file */
2305     afs_RemoveVCB(afid);
2306     afs_ProcessFS(tvc, OutStatus, areq);
2307     tvc->callback = tc->srvr->server;
2308
2309     /* we use osi_Time twice below.  Ideally, we would use the time at which 
2310      * the FetchStatus call began, instead, but we don't have it here.  So we
2311      * make do with "now".  In the CRO case, it doesn't really matter. In 
2312      * the other case, we hope that the difference between "now" and when the 
2313      * call actually began execution on the server won't be larger than the
2314      * padding which the server keeps.  Subtract 1 second anyway, to be on 
2315      * the safe side.  Can't subtract more because we don't know how big
2316      * ExpirationTime is.  Possible consistency problems may arise if the call
2317      * timeout period becomes longer than the server's expiration padding.  */
2318     ObtainWriteLock(&afs_xcbhash, 470);
2319     if (CallBack->ExpirationTime != 0) {
2320         tvc->cbExpires = CallBack->ExpirationTime+osi_Time()-1; 
2321         tvc->states |= CStatd;
2322         tvc->states &= ~CBulkFetching;
2323         afs_QueueCallback(tvc, CBHash(CallBack->ExpirationTime), tvp);
2324         }
2325     else if (tvc->states & CRO) {
2326        /* old-fashioned AFS 3.2 style */
2327        tvc->cbExpires = 3600+osi_Time(); /*XXX*/
2328        tvc->states |= CStatd;
2329        tvc->states &= ~CBulkFetching;
2330        afs_QueueCallback(tvc, CBHash(3600), tvp); 
2331      }
2332     else {
2333       afs_DequeueCallback(tvc);
2334       tvc->callback = (struct server *)0;
2335       tvc->states &= ~(CStatd|CUnique);  
2336       if ((tvc->states & CForeign) || (tvc->fid.Fid.Vnode & 1)) 
2337         osi_dnlc_purgedp (tvc);  /* if it (could be) a directory */
2338     }
2339     ReleaseWriteLock(&afs_xcbhash);
2340     if ( tvp )
2341         afs_PutVolume(tvp, READ_LOCK);
2342         
2343     /* look in per-pag cache */
2344       if (tvc->Access && (ac = afs_FindAxs(tvc->Access, areq->uid)))
2345           ac->axess = OutStatus->CallerAccess;   /* substitute pags */
2346       else  /* not found, add a new one if possible */
2347           afs_AddAxs(tvc->Access, areq->uid, OutStatus->CallerAccess);
2348
2349     ReleaseWriteLock(&tvc->lock);
2350     afs_Trace4(afs_iclSetp, CM_TRACE_STUFFVCACHE, ICL_TYPE_POINTER, tvc,
2351                ICL_TYPE_POINTER, tvc->callback, ICL_TYPE_INT32, tvc->cbExpires,
2352                ICL_TYPE_INT32, tvc->cbExpires-osi_Time());
2353     /*
2354      * Release ref count... hope this guy stays around...
2355      */
2356     afs_PutVCache(tvc, WRITE_LOCK);
2357 } /*afs_StuffVcache*/
2358 #endif
2359
2360 /*
2361  * afs_PutVCache
2362  *
2363  * Description:
2364  *      Decrements the reference count on a cache entry.
2365  *
2366  * Parameters:
2367  *      avc : Pointer to the cache entry to decrement.
2368  *
2369  * Environment:
2370  *      Nothing interesting.
2371  */
2372 void
2373 afs_PutVCache(avc, locktype)
2374     register struct vcache *avc;
2375     afs_int32 locktype;
2376 { /*afs_PutVCache*/
2377
2378     AFS_STATCNT(afs_PutVCache);
2379     /*
2380      * Can we use a read lock here?
2381      */
2382     ObtainReadLock(&afs_xvcache);
2383     AFS_FAST_RELE(avc);
2384     ReleaseReadLock(&afs_xvcache);
2385 } /*afs_PutVCache*/
2386
2387 /*
2388  * afs_FindVCache
2389  *
2390  * Description:
2391  *      Find a vcache entry given a fid.
2392  *
2393  * Parameters:
2394  *      afid : Pointer to the fid whose cache entry we desire.
2395  *      retry: (SGI-specific) tell the caller to drop the lock on xvcache, 
2396  *             unlock the vnode, and try again.
2397  *      flags: bit 1 to specify whether to compute hit statistics.  Not
2398  *             set if FindVCache is called as part of internal bookkeeping.
2399  *
2400  * Environment:
2401  *      Must be called with the afs_xvcache lock at least held at
2402  *      the read level.  In order to do the VLRU adjustment, the xvcache lock
2403  *      must be shared-- we upgrade it here.
2404  */
2405
2406 struct vcache *afs_FindVCache(struct VenusFid *afid, afs_int32 lockit,
2407                               afs_int32 locktype, afs_int32 *retry, afs_int32 flag)
2408 {
2409
2410     register struct vcache *tvc;
2411     afs_int32 i;
2412
2413     AFS_STATCNT(afs_FindVCache);
2414
2415     i = VCHash(afid);
2416     for(tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2417         if (FidMatches(afid, tvc)) {
2418 #ifdef  AFS_OSF_ENV
2419             /* Grab this vnode, possibly reactivating from the free list */
2420             int vg;
2421             AFS_GUNLOCK();
2422             vg = vget(AFSTOV(tvc));
2423             AFS_GLOCK();
2424             if (vg)
2425                 continue;
2426 #endif  /* AFS_OSF_ENV */
2427             break;
2428         }
2429     }
2430
2431     /* should I have a read lock on the vnode here? */
2432     if (tvc) {
2433         if (retry) *retry = 0;
2434 #if !defined(AFS_OSF_ENV)
2435         osi_vnhold(tvc, retry);  /* already held, above */
2436         if (retry && *retry) 
2437           return 0;
2438 #endif
2439         /*
2440          * only move to front of vlru if we have proper vcache locking)
2441          */
2442         if (flag & DO_VLRU) {
2443            if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2444               refpanic ("FindVC VLRU inconsistent1");
2445            }
2446            if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2447               refpanic ("FindVC VLRU inconsistent1");
2448            }
2449            if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2450               refpanic ("FindVC VLRU inconsistent2");
2451            }
2452             UpgradeSToWLock(&afs_xvcache,26);
2453             QRemove(&tvc->vlruq);
2454             QAdd(&VLRU, &tvc->vlruq);
2455             ConvertWToSLock(&afs_xvcache);
2456            if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2457               refpanic ("FindVC VLRU inconsistent1");
2458            }
2459            if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2460               refpanic ("FindVC VLRU inconsistent2");
2461            }
2462            if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2463               refpanic ("FindVC VLRU inconsistent3");
2464            }
2465         }
2466         vcachegen++;
2467     } 
2468
2469     if (flag & DO_STATS) {
2470       if (tvc)  afs_stats_cmperf.vcacheHits++;
2471       else      afs_stats_cmperf.vcacheMisses++;
2472       if (afid->Cell == LOCALCELL)
2473         afs_stats_cmperf.vlocalAccesses++;
2474       else
2475         afs_stats_cmperf.vremoteAccesses++;
2476     }
2477
2478 #ifdef AFS_LINUX22_ENV
2479     if (tvc && (tvc->states & CStatd))
2480         vcache2inode(tvc); /* mainly to reset i_nlink */
2481 #endif
2482 #ifdef AFS_DARWIN_ENV
2483     if (tvc)
2484         osi_VM_Setup(tvc);
2485 #endif
2486     return tvc;
2487 } /*afs_FindVCache*/
2488
2489 /*
2490  * afs_NFSFindVCache
2491  *
2492  * Description:
2493  *      Find a vcache entry given a fid. Does a wildcard match on what we
2494  *      have for the fid. If more than one entry, don't return anything.
2495  *
2496  * Parameters:
2497  *      avcp : Fill in pointer if we found one and only one.
2498  *      afid : Pointer to the fid whose cache entry we desire.
2499  *      retry: (SGI-specific) tell the caller to drop the lock on xvcache, 
2500  *             unlock the vnode, and try again.
2501  *      flags: bit 1 to specify whether to compute hit statistics.  Not
2502  *             set if FindVCache is called as part of internal bookkeeping.
2503  *
2504  * Environment:
2505  *      Must be called with the afs_xvcache lock at least held at
2506  *      the read level.  In order to do the VLRU adjustment, the xvcache lock
2507  *      must be shared-- we upgrade it here.
2508  *
2509  * Return value:
2510  *      number of matches found.
2511  */
2512
2513 int afs_duplicate_nfs_fids=0;
2514
2515 afs_int32 afs_NFSFindVCache(avcp, afid, lockit)
2516      struct vcache **avcp;
2517     struct VenusFid *afid;
2518     afs_int32 lockit;
2519 { /*afs_FindVCache*/
2520
2521     register struct vcache *tvc;
2522     afs_int32 i;
2523     afs_int32 retry = 0;
2524     afs_int32 count = 0;
2525     struct vcache *found_tvc = NULL;
2526
2527     AFS_STATCNT(afs_FindVCache);
2528
2529  loop:
2530
2531     ObtainSharedLock(&afs_xvcache,331); 
2532
2533     i = VCHash(afid);
2534     for(tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2535         /* Match only on what we have.... */
2536         if (((tvc->fid.Fid.Vnode & 0xffff) == afid->Fid.Vnode)
2537             && (tvc->fid.Fid.Volume == afid->Fid.Volume)
2538             && ((tvc->fid.Fid.Unique & 0xffffff) == afid->Fid.Unique)
2539             && (tvc->fid.Cell == afid->Cell)) {
2540 #ifdef  AFS_OSF_ENV
2541             /* Grab this vnode, possibly reactivating from the free list */
2542             int vg;
2543             AFS_GUNLOCK();
2544             vg = vget(AFSTOV(tvc));
2545             AFS_GLOCK();
2546             if (vg) {
2547                 /* This vnode no longer exists. */
2548                 continue;
2549             }
2550 #endif  /* AFS_OSF_ENV */
2551             count ++;
2552             if (found_tvc) {
2553                 /* Duplicates */
2554 #ifdef AFS_OSF_ENV
2555                 /* Drop our reference counts. */
2556                 vrele(AFSTOV(tvc));
2557                 vrele(AFSTOV(found_tvc));
2558 #endif
2559                 afs_duplicate_nfs_fids++;
2560                 ReleaseSharedLock(&afs_xvcache);
2561                 return count;
2562             }
2563             found_tvc = tvc;
2564         }
2565     }
2566
2567     tvc = found_tvc;
2568     /* should I have a read lock on the vnode here? */
2569     if (tvc) {
2570 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI53_ENV)
2571         osi_vnhold(tvc, &retry); 
2572         if (retry) {
2573             count = 0;
2574             found_tvc = (struct vcache*)0;
2575             ReleaseSharedLock(&afs_xvcache);
2576             spunlock_psema(tvc->v.v_lock, retry, &tvc->v.v_sync, PINOD);
2577             goto loop;
2578         }
2579 #else
2580 #if !defined(AFS_OSF_ENV)
2581         osi_vnhold(tvc, (int*)0);  /* already held, above */
2582 #endif
2583 #endif
2584         /*
2585          * We obtained the xvcache lock above.
2586          */
2587         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2588             refpanic ("FindVC VLRU inconsistent1");
2589         }
2590         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2591             refpanic ("FindVC VLRU inconsistent1");
2592         }
2593         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2594             refpanic ("FindVC VLRU inconsistent2");
2595         }
2596         UpgradeSToWLock(&afs_xvcache,568);
2597         QRemove(&tvc->vlruq);
2598         QAdd(&VLRU, &tvc->vlruq);
2599         ConvertWToSLock(&afs_xvcache);
2600         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
2601             refpanic ("FindVC VLRU inconsistent1");
2602         }
2603         if (tvc->vlruq.next->prev != &(tvc->vlruq)) {
2604             refpanic ("FindVC VLRU inconsistent2");
2605         }
2606         if (tvc->vlruq.prev->next != &(tvc->vlruq)) {
2607             refpanic ("FindVC VLRU inconsistent3");
2608         }
2609     }
2610     vcachegen++;
2611
2612     if (tvc)    afs_stats_cmperf.vcacheHits++;
2613     else        afs_stats_cmperf.vcacheMisses++;
2614     if (afid->Cell == LOCALCELL)
2615         afs_stats_cmperf.vlocalAccesses++;
2616     else
2617         afs_stats_cmperf.vremoteAccesses++;
2618
2619     *avcp = tvc; /* May be null */
2620
2621     ReleaseSharedLock(&afs_xvcache);
2622     return (tvc ? 1 : 0);
2623
2624 } /*afs_NFSFindVCache*/
2625
2626
2627
2628
2629 /*
2630  * afs_vcacheInit
2631  *
2632  * Initialize vcache related variables
2633  */
2634 void afs_vcacheInit(int astatSize)
2635 {
2636     register struct vcache *tvp;
2637     int i;
2638 #if     defined(AFS_OSF_ENV)
2639     if (!afs_maxvcount) {
2640 #if     defined(AFS_OSF30_ENV)
2641         afs_maxvcount = max_vnodes/2;  /* limit ourselves to half the total */
2642 #else
2643         afs_maxvcount = nvnode/2;  /* limit ourselves to half the total */  
2644 #endif 
2645         if (astatSize < afs_maxvcount) {
2646             afs_maxvcount = astatSize;
2647         }
2648     }
2649 #else   /* AFS_OSF_ENV */
2650     freeVCList = (struct vcache *)0;
2651 #endif
2652
2653     RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2654     LOCK_INIT(&afs_xvcb, "afs_xvcb");
2655
2656 #if     !defined(AFS_OSF_ENV)
2657     /* Allocate and thread the struct vcache entries */
2658     tvp = (struct vcache *) afs_osi_Alloc(astatSize * sizeof(struct vcache));
2659     memset((char *)tvp, 0, sizeof(struct vcache)*astatSize);
2660
2661     Initial_freeVCList = tvp;
2662     freeVCList = &(tvp[0]);
2663     for(i=0; i < astatSize-1; i++) {
2664        tvp[i].nextfree = &(tvp[i+1]);
2665     }   
2666     tvp[astatSize-1].nextfree = (struct vcache *) 0;
2667 #ifdef  AFS_AIX32_ENV
2668     pin((char *)tvp, astatSize * sizeof(struct vcache));        /* XXX */    
2669 #endif
2670 #endif
2671
2672
2673 #if defined(AFS_SGI_ENV)
2674     for(i=0; i < astatSize; i++) {
2675         char name[METER_NAMSZ];
2676         struct vcache *tvc = &tvp[i];
2677
2678         tvc->v.v_number = ++afsvnumbers;
2679         tvc->vc_rwlockid = OSI_NO_LOCKID;
2680         initnsema(&tvc->vc_rwlock, 1, makesname(name, "vrw", tvc->v.v_number));
2681 #ifndef AFS_SGI53_ENV
2682         initnsema(&tvc->v.v_sync, 0, makesname(name, "vsy", tvc->v.v_number));
2683 #endif
2684 #ifndef AFS_SGI62_ENV
2685         initnlock(&tvc->v.v_lock, makesname(name, "vlk", tvc->v.v_number));
2686 #endif /* AFS_SGI62_ENV */
2687     }
2688 #endif
2689
2690     QInit(&VLRU);
2691
2692
2693 }
2694
2695 /*
2696  * shutdown_vcache
2697  *
2698  */
2699 void shutdown_vcache(void)
2700 {
2701     int i;
2702     struct afs_cbr *tsp, *nsp;
2703     /*
2704      * XXX We may potentially miss some of the vcaches because if when there're no
2705      * free vcache entries and all the vcache entries are active ones then we allocate
2706      * an additional one - admittedly we almost never had that occur.
2707      */
2708 #if     !defined(AFS_OSF_ENV)
2709     afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2710 #endif
2711 #ifdef  AFS_AIX32_ENV
2712     unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
2713 #endif
2714
2715     {
2716         register struct afs_q *tq, *uq;
2717         register struct vcache *tvc;
2718         for (tq = VLRU.prev; tq != &VLRU; tq = uq) {
2719             tvc = QTOV(tq);
2720             uq = QPrev(tq);
2721             if (tvc->mvid) {
2722                 osi_FreeSmallSpace(tvc->mvid);
2723                 tvc->mvid = (struct VenusFid*)0;
2724             }
2725 #ifdef  AFS_AIX_ENV
2726             aix_gnode_rele(AFSTOV(tvc));
2727 #endif
2728             if (tvc->linkData) {
2729                 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
2730                 tvc->linkData = 0;
2731             }
2732         }
2733         /* 
2734          * Also free the remaining ones in the Cache 
2735          */
2736         for (i=0; i < VCSIZE; i++) {
2737             for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
2738                 if (tvc->mvid) {
2739                     osi_FreeSmallSpace(tvc->mvid);
2740                     tvc->mvid = (struct VenusFid*)0;
2741                 }
2742 #ifdef  AFS_AIX_ENV
2743                 if (tvc->v.v_gnode)
2744                     afs_osi_Free(tvc->v.v_gnode, sizeof(struct gnode));
2745 #ifdef  AFS_AIX32_ENV
2746                 if (tvc->segid) {
2747                     AFS_GUNLOCK();
2748                     vms_delete(tvc->segid);
2749                     AFS_GLOCK();
2750                     tvc->segid = tvc->vmh = NULL;
2751                     if (VREFCOUNT(tvc)) osi_Panic("flushVcache: vm race");
2752                 }
2753                 if (tvc->credp) {
2754                     crfree(tvc->credp);
2755                     tvc->credp = NULL;
2756                 }
2757 #endif
2758 #endif
2759 #if     defined(AFS_SUN5_ENV)
2760                 if (tvc->credp) {
2761                     crfree(tvc->credp);
2762                     tvc->credp = NULL;
2763                 }
2764 #endif
2765                 if (tvc->linkData) {
2766                     afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
2767                     tvc->linkData = 0;
2768                 }
2769
2770                 afs_FreeAllAxs(&(tvc->Access));
2771             }
2772             afs_vhashT[i] = 0;
2773         }
2774     }
2775     /*
2776      * Free any leftover callback queue
2777      */
2778     for (tsp = afs_cbrSpace; tsp; tsp = nsp ) {
2779         nsp = tsp->next;
2780         afs_osi_Free((char *)tsp, AFS_NCBRS * sizeof(struct afs_cbr));
2781     }
2782     afs_cbrSpace = 0;
2783
2784 #if     !defined(AFS_OSF_ENV)
2785     freeVCList = Initial_freeVCList = 0;
2786 #endif
2787     RWLOCK_INIT(&afs_xvcache, "afs_xvcache");
2788     LOCK_INIT(&afs_xvcb, "afs_xvcb");
2789     QInit(&VLRU);
2790
2791 }