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