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