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