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