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