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