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