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