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