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