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