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