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