1b402839cfe9d9c10099e74bcd6a125db3ea58b3
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.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_lookup
13  * EvalMountPoint
14  * afs_DoBulkStat
15  */
16
17 #include <afsconfig.h>
18 #include "afs/param.h"
19
20 RCSID
21     ("$Header$");
22
23 #include "afs/sysincludes.h"    /* Standard vendor system headers */
24 #include "afsincludes.h"        /* Afs-based standard headers */
25 #include "afs/afs_stats.h"      /* statistics */
26 #include "afs/afs_cbqueue.h"
27 #include "afs/nfsclient.h"
28 #include "afs/exporter.h"
29 #include "afs/afs_osidnlc.h"
30
31
32 extern struct DirEntry *afs_dir_GetBlob();
33
34
35 afs_int32 afs_bkvolpref = 0;
36 afs_int32 afs_bulkStatsDone;
37 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
38 int afs_fakestat_enable = 0;    /* 1: fakestat-all, 2: fakestat-crosscell */
39
40
41 /* this would be faster if it did comparison as int32word, but would be 
42  * dependant on byte-order and alignment, and I haven't figured out
43  * what "@sys" is in binary... */
44 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
45
46 /* call under write lock, evaluate mvid field from a mt pt.
47  * avc is the vnode of the mount point object; must be write-locked.
48  * advc is the vnode of the containing directory (optional; if NULL and
49  *   EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
50  * avolpp is where we return a pointer to the volume named by the mount pt, if success
51  * areq is the identity of the caller.
52  *
53  * NOTE: this function returns a held volume structure in *volpp if it returns 0!
54  */
55 int
56 EvalMountPoint(register struct vcache *avc, struct vcache *advc,
57                struct volume **avolpp, register struct vrequest *areq)
58 {
59     afs_int32 code;
60     struct volume *tvp = 0;
61     struct VenusFid tfid;
62     struct cell *tcell;
63     char *cpos, *volnamep;
64     char type, *buf;
65     afs_int32 prefetch;         /* 1=>None  2=>RO  3=>BK */
66     afs_int32 mtptCell, assocCell = 0, hac = 0;
67     afs_int32 samecell, roname, len;
68
69     AFS_STATCNT(EvalMountPoint);
70 #ifdef notdef
71     if (avc->mvid && (avc->states & CMValid))
72         return 0;               /* done while racing */
73 #endif
74     *avolpp = NULL;
75     code = afs_HandleLink(avc, areq);
76     if (code)
77         return code;
78
79     /* Determine which cell and volume the mointpoint goes to */
80     type = avc->linkData[0];    /* '#'=>Regular '%'=>RW */
81     cpos = afs_strchr(&avc->linkData[1], ':');  /* if cell name present */
82     if (cpos) {
83         volnamep = cpos + 1;
84         *cpos = 0;
85         tcell = afs_GetCellByName(&avc->linkData[1], READ_LOCK);
86         *cpos = ':';
87     } else {
88         volnamep = &avc->linkData[1];
89         tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
90     }
91     if (!tcell)
92         return ENODEV;
93
94     mtptCell = tcell->cellNum;  /* The cell for the mountpoint */
95     if (tcell->lcellp) {
96         hac = 1;                /* has associated cell */
97         assocCell = tcell->lcellp->cellNum;     /* The associated cell */
98     }
99     afs_PutCell(tcell, READ_LOCK);
100
101     /* Is volume name a "<n>.backup" or "<n>.readonly" name */
102     len = strlen(volnamep);
103     roname = ((len > 9) && (strcmp(&volnamep[len - 9], ".readonly") == 0))
104         || ((len > 7) && (strcmp(&volnamep[len - 7], ".backup") == 0));
105
106     /* When we cross mountpoint, do we stay in the same cell */
107     samecell = (avc->fid.Cell == mtptCell) || (hac
108                                                && (avc->fid.Cell ==
109                                                    assocCell));
110
111     /* Decide whether to prefetch the BK, or RO.  Also means we want the BK or
112      * RO.
113      * If this is a regular mountpoint with a RW volume name
114      * - If BK preference is enabled AND we remain within the same cell AND
115      *   start from a BK volume, then we will want to prefetch the BK volume.
116      * - If we cross a cell boundary OR start from a RO volume, then we will
117      *   want to prefetch the RO volume.
118      */
119     if ((type == '#') && !roname) {
120         if (afs_bkvolpref && samecell && (avc->states & CBackup))
121             prefetch = 3;       /* Prefetch the BK */
122         else if (!samecell || (avc->states & CRO))
123             prefetch = 2;       /* Prefetch the RO */
124         else
125             prefetch = 1;       /* Do not prefetch */
126     } else {
127         prefetch = 1;           /* Do not prefetch */
128     }
129
130     /* Get the volume struct. Unless this volume name has ".readonly" or
131      * ".backup" in it, this will get the volume struct for the RW volume.
132      * The RO volume will be prefetched if requested (but not returned).
133      */
134     tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK);
135
136     /* If no volume was found in this cell, try the associated linked cell */
137     if (!tvp && hac && areq->volumeError) {
138         tvp =
139             afs_GetVolumeByName(volnamep, assocCell, prefetch, areq,
140                                 WRITE_LOCK);
141     }
142
143     /* Still not found. If we are looking for the RO, then perhaps the RW 
144      * doesn't exist? Try adding ".readonly" to volname and look for that.
145      * Don't know why we do this. Would have still found it in above call - jpm.
146      */
147     if (!tvp && (prefetch == 2) && len < AFS_SMALLOCSIZ - 10) {
148         buf = (char *)osi_AllocSmallSpace(len + 10);
149
150         strcpy(buf, volnamep);
151         afs_strcat(buf, ".readonly");
152
153         tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
154
155         /* Try the associated linked cell if failed */
156         if (!tvp && hac && areq->volumeError) {
157             tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
158         }
159         osi_FreeSmallSpace(buf);
160     }
161
162     if (!tvp)
163         return ENODEV;          /* Couldn't find the volume */
164
165     /* Don't cross mountpoint from a BK to a BK volume */
166     if ((avc->states & CBackup) && (tvp->states & VBackup)) {
167         afs_PutVolume(tvp, WRITE_LOCK);
168         return ENODEV;
169     }
170
171     /* If we want (prefetched) the BK and it exists, then drop the RW volume
172      * and get the BK.
173      * Otherwise, if we want (prefetched0 the RO and it exists, then drop the
174      * RW volume and get the RO.
175      * Otherwise, go with the RW.
176      */
177     if ((prefetch == 3) && tvp->backVol) {
178         tfid.Fid.Volume = tvp->backVol; /* remember BK volume */
179         tfid.Cell = tvp->cell;
180         afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
181         tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK);   /* get the new one */
182         if (!tvp)
183             return ENODEV;      /* oops, can't do it */
184     } else if ((prefetch >= 2) && tvp->roVol) {
185         tfid.Fid.Volume = tvp->roVol;   /* remember RO volume */
186         tfid.Cell = tvp->cell;
187         afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
188         tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK);   /* get the new one */
189         if (!tvp)
190             return ENODEV;      /* oops, can't do it */
191     }
192
193     if (avc->mvid == 0)
194         avc->mvid =
195             (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
196     avc->mvid->Cell = tvp->cell;
197     avc->mvid->Fid.Volume = tvp->volume;
198     avc->mvid->Fid.Vnode = 1;
199     avc->mvid->Fid.Unique = 1;
200     avc->states |= CMValid;
201
202     /* Used to: if the mount point is stored within a backup volume,
203      * then we should only update the parent pointer information if
204      * there's none already set, so as to avoid updating a volume's ..
205      * info with something in an OldFiles directory.
206      *
207      * Next two lines used to be under this if:
208      *
209      * if (!(avc->states & CBackup) || tvp->dotdot.Fid.Volume == 0)
210      *
211      * Now: update mount point back pointer on every call, so that we handle
212      * multiple mount points better.  This way, when du tries to go back
213      * via chddir(".."), it will end up exactly where it started, yet
214      * cd'ing via a new path to a volume will reset the ".." pointer
215      * to the new path.
216      */
217     tvp->mtpoint = avc->fid;    /* setup back pointer to mtpoint */
218     if (advc)
219         tvp->dotdot = advc->fid;
220
221     *avolpp = tvp;
222     return 0;
223 }
224
225 /*
226  * afs_InitFakeStat
227  *
228  * Must be called on an afs_fakestat_state object before calling
229  * afs_EvalFakeStat or afs_PutFakeStat.  Calling afs_PutFakeStat
230  * without calling afs_EvalFakeStat is legal, as long as this
231  * function is called.
232  */
233 void
234 afs_InitFakeStat(struct afs_fakestat_state *state)
235 {
236     if (!afs_fakestat_enable)
237         return;
238
239     state->valid = 1;
240     state->did_eval = 0;
241     state->need_release = 0;
242 }
243
244 /*
245  * afs_EvalFakeStat_int
246  *
247  * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
248  * which is called by those wrapper functions.
249  *
250  * Only issues RPCs if canblock is non-zero.
251  */
252 static int
253 afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
254                      struct vrequest *areq, int canblock)
255 {
256     struct vcache *tvc, *root_vp;
257     struct volume *tvolp = NULL;
258     int code = 0;
259
260     if (!afs_fakestat_enable)
261         return 0;
262
263     osi_Assert(state->valid == 1);
264     osi_Assert(state->did_eval == 0);
265     state->did_eval = 1;
266
267     tvc = *avcp;
268     if (tvc->mvstat != 1)
269         return 0;
270
271     /* Is the call to VerifyVCache really necessary? */
272     code = afs_VerifyVCache(tvc, areq);
273     if (code)
274         goto done;
275     if (canblock) {
276         ObtainWriteLock(&tvc->lock, 599);
277         code = EvalMountPoint(tvc, NULL, &tvolp, areq);
278         ReleaseWriteLock(&tvc->lock);
279         if (code)
280             goto done;
281         if (tvolp) {
282             tvolp->dotdot = tvc->fid;
283             tvolp->dotdot.Fid.Vnode = tvc->parentVnode;
284             tvolp->dotdot.Fid.Unique = tvc->parentUnique;
285         }
286     }
287     if (tvc->mvid && (tvc->states & CMValid)) {
288         if (!canblock) {
289             afs_int32 retry;
290
291             do {
292                 retry = 0;
293                 ObtainWriteLock(&afs_xvcache, 597);
294                 root_vp = afs_FindVCache(tvc->mvid, &retry, IS_WLOCK);
295                 if (root_vp && retry) {
296                     ReleaseWriteLock(&afs_xvcache);
297                     afs_PutVCache(root_vp);
298                 }
299             } while (root_vp && retry);
300             ReleaseWriteLock(&afs_xvcache);
301         } else {
302             root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
303         }
304         if (!root_vp) {
305             code = canblock ? ENOENT : 0;
306             goto done;
307         }
308 #ifdef AFS_DARWIN80_ENV
309         root_vp->m.Type = VDIR;
310         AFS_GUNLOCK();
311         code = afs_darwin_finalizevnode(root_vp, NULL, NULL, 0);
312         AFS_GLOCK();
313         if (code) goto done;
314         vnode_ref(AFSTOV(root_vp));
315 #endif
316         if (tvolp) {
317             /* Is this always kosher?  Perhaps we should instead use
318              * NBObtainWriteLock to avoid potential deadlock.
319              */
320             ObtainWriteLock(&root_vp->lock, 598);
321             if (!root_vp->mvid)
322                 root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
323             *root_vp->mvid = tvolp->dotdot;
324             ReleaseWriteLock(&root_vp->lock);
325         }
326         state->need_release = 1;
327         state->root_vp = root_vp;
328         *avcp = root_vp;
329         code = 0;
330     } else {
331         code = canblock ? ENOENT : 0;
332     }
333
334   done:
335     if (tvolp)
336         afs_PutVolume(tvolp, WRITE_LOCK);
337     return code;
338 }
339
340 /*
341  * afs_EvalFakeStat
342  *
343  * Automatically does the equivalent of EvalMountPoint for vcache entries
344  * which are mount points.  Remembers enough state to properly release
345  * the volume root vcache when afs_PutFakeStat() is called.
346  *
347  * State variable must be initialized by afs_InitFakeState() beforehand.
348  *
349  * Returns 0 when everything succeeds and *avcp points to the vcache entry
350  * that should be used for the real vnode operation.  Returns non-zero if
351  * something goes wrong and the error code should be returned to the user.
352  */
353 int
354 afs_EvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
355                  struct vrequest *areq)
356 {
357     return afs_EvalFakeStat_int(avcp, state, areq, 1);
358 }
359
360 /*
361  * afs_TryEvalFakeStat
362  *
363  * Same as afs_EvalFakeStat, but tries not to talk to remote servers
364  * and only evaluate the mount point if all the data is already in
365  * local caches.
366  *
367  * Returns 0 if everything succeeds and *avcp points to a valid
368  * vcache entry (possibly evaluated).
369  */
370 int
371 afs_TryEvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
372                     struct vrequest *areq)
373 {
374     return afs_EvalFakeStat_int(avcp, state, areq, 0);
375 }
376
377 /*
378  * afs_PutFakeStat
379  *
380  * Perform any necessary cleanup at the end of a vnode op, given that
381  * afs_InitFakeStat was previously called with this state.
382  */
383 void
384 afs_PutFakeStat(struct afs_fakestat_state *state)
385 {
386     if (!afs_fakestat_enable)
387         return;
388
389     osi_Assert(state->valid == 1);
390     if (state->need_release)
391         afs_PutVCache(state->root_vp);
392     state->valid = 0;
393 }
394
395 int
396 afs_ENameOK(register char *aname)
397 {
398     register int tlen;
399
400     AFS_STATCNT(ENameOK);
401     tlen = strlen(aname);
402     if (tlen >= 4 && strcmp(aname + tlen - 4, "@sys") == 0)
403         return 0;
404     return 1;
405 }
406
407 static int
408 afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
409                register char *bufp, int *num, char **sysnamelist[])
410 {
411     register struct unixuser *au;
412     register afs_int32 error;
413
414     AFS_STATCNT(getsysname);
415
416     *sysnamelist = afs_sysnamelist;
417
418     if (!afs_nfsexporter)
419         strcpy(bufp, (*sysnamelist)[0]);
420     else {
421         au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
422         if (au->exporter) {
423             error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
424             if (error) {
425                 strcpy(bufp, "@sys");
426                 afs_PutUser(au, 0);
427                 return -1;
428             } else {
429                 strcpy(bufp, (*sysnamelist)[0]);
430             }
431         } else
432             strcpy(bufp, afs_sysname);
433         afs_PutUser(au, 0);
434     }
435     return 0;
436 }
437
438 void
439 Check_AtSys(register struct vcache *avc, const char *aname,
440             struct sysname_info *state, struct vrequest *areq)
441 {
442     int num = 0;
443     char **sysnamelist[MAXNUMSYSNAMES];
444
445     if (AFS_EQ_ATSYS(aname)) {
446         state->offset = 0;
447         state->name = (char *)osi_AllocLargeSpace(AFS_SMALLOCSIZ);
448         state->allocked = 1;
449         state->index =
450             afs_getsysname(areq, avc, state->name, &num, sysnamelist);
451     } else {
452         state->offset = -1;
453         state->allocked = 0;
454         state->index = 0;
455         state->name = (char *)aname;
456     }
457 }
458
459 int
460 Next_AtSys(register struct vcache *avc, struct vrequest *areq,
461            struct sysname_info *state)
462 {
463     int num = afs_sysnamecount;
464     char **sysnamelist[MAXNUMSYSNAMES];
465
466     if (state->index == -1)
467         return 0;               /* No list */
468
469     /* Check for the initial state of aname != "@sys" in Check_AtSys */
470     if (state->offset == -1 && state->allocked == 0) {
471         register char *tname;
472
473         /* Check for .*@sys */
474         for (tname = state->name; *tname; tname++)
475             /*Move to the end of the string */ ;
476
477         if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
478             state->offset = (tname - 4) - state->name;
479             tname = (char *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
480             strncpy(tname, state->name, state->offset);
481             state->name = tname;
482             state->allocked = 1;
483             num = 0;
484             state->index =
485                 afs_getsysname(areq, avc, state->name + state->offset, &num,
486                                sysnamelist);
487             return 1;
488         } else
489             return 0;           /* .*@sys doesn't match either */
490     } else {
491         register struct unixuser *au;
492         register afs_int32 error;
493
494         *sysnamelist = afs_sysnamelist;
495
496         if (afs_nfsexporter) {
497             au = afs_GetUser(areq->uid, avc->fid.Cell, 0);
498             if (au->exporter) {
499                 error =
500                     EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
501                 if (error) {
502                     return 0;
503                 }
504             }
505             afs_PutUser(au, 0);
506         }
507         if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
508             return 0;           /* end of list */
509     }
510     strcpy(state->name + state->offset, (*sysnamelist)[(unsigned int)state->index]);
511     return 1;
512 }
513
514 extern int BlobScan(struct dcache * afile, afs_int32 ablob);
515
516 /* called with an unlocked directory and directory cookie.  Areqp
517  * describes who is making the call.
518  * Scans the next N (about 30, typically) directory entries, and does
519  * a bulk stat call to stat them all.
520  *
521  * Must be very careful when merging in RPC responses, since we dont
522  * want to overwrite newer info that was added by a file system mutating
523  * call that ran concurrently with our bulk stat call.
524  *
525  * We do that, as described below, by not merging in our info (always
526  * safe to skip the merge) if the status info is valid in the vcache entry.
527  *
528  * If adapt ever implements the bulk stat RPC, then this code will need to
529  * ensure that vcaches created for failed RPC's to older servers have the
530  * CForeign bit set.
531  */
532 static struct vcache *BStvc = NULL;
533
534 int
535 afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
536 {
537     int nentries;               /* # of entries to prefetch */
538     int nskip;                  /* # of slots in the LRU queue to skip */
539     struct vcache *lruvcp;      /* vcache ptr of our goal pos in LRU queue */
540     struct dcache *dcp;         /* chunk containing the dir block */
541     char *statMemp;             /* status memory block */
542     char *cbfMemp;              /* callback and fid memory block */
543     afs_size_t temp;            /* temp for holding chunk length, &c. */
544     struct AFSFid *fidsp;       /* file IDs were collecting */
545     struct AFSCallBack *cbsp;   /* call back pointers */
546     struct AFSCallBack *tcbp;   /* temp callback ptr */
547     struct AFSFetchStatus *statsp;      /* file status info */
548     struct AFSVolSync volSync;  /* vol sync return info */
549     struct vcache *tvcp;        /* temp vcp */
550     struct afs_q *tq;           /* temp queue variable */
551     AFSCBFids fidParm;          /* file ID parm for bulk stat */
552     AFSBulkStats statParm;      /* stat info parm for bulk stat */
553     int fidIndex = 0;           /* which file were stating */
554     struct conn *tcp = 0;       /* conn for call */
555     AFSCBs cbParm;              /* callback parm for bulk stat */
556     struct server *hostp = 0;   /* host we got callback from */
557     long startTime;             /* time we started the call,
558                                  * for callback expiration base
559                                  */
560     afs_size_t statSeqNo = 0;   /* Valued of file size to detect races */
561     int code;                   /* error code */
562     long newIndex;              /* new index in the dir */
563     struct DirEntry *dirEntryp; /* dir entry we are examining */
564     int i;
565     struct VenusFid afid;       /* file ID we are using now */
566     struct VenusFid tfid;       /* another temp. file ID */
567     afs_int32 retry;            /* handle low-level SGI MP race conditions */
568     long volStates;             /* flags from vol structure */
569     struct volume *volp = 0;    /* volume ptr */
570     struct VenusFid dotdot;
571     int flagIndex = 0;          /* First file with bulk fetch flag set */
572     int inlinebulk = 0;         /* Did we use InlineBulk RPC or not? */
573     XSTATS_DECLS;
574 #ifdef AFS_DARWIN80_ENV
575     panic("bulkstatus doesn't work on AFS_DARWIN80_ENV. don't call it");
576 #endif
577     /* first compute some basic parameters.  We dont want to prefetch more
578      * than a fraction of the cache in any given call, and we want to preserve
579      * a portion of the LRU queue in any event, so as to avoid thrashing
580      * the entire stat cache (we will at least leave some of it alone).
581      * presently dont stat more than 1/8 the cache in any one call.      */
582     nentries = afs_cacheStats / 8;
583
584     /* dont bother prefetching more than one calls worth of info */
585     if (nentries > AFSCBMAX)
586         nentries = AFSCBMAX;
587
588     /* heuristic to make sure that things fit in 4K.  This means that
589      * we shouldnt make it any bigger than 47 entries.  I am typically
590      * going to keep it a little lower, since we don't want to load
591      * too much of the stat cache.
592      */
593     if (nentries > 30)
594         nentries = 30;
595
596     /* now, to reduce the stack size, well allocate two 4K blocks,
597      * one for fids and callbacks, and one for stat info.  Well set
598      * up our pointers to the memory from there, too.
599      */
600     statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
601     statsp = (struct AFSFetchStatus *)statMemp;
602     cbfMemp =
603         osi_AllocLargeSpace(nentries *
604                             (sizeof(AFSCallBack) + sizeof(AFSFid)));
605     fidsp = (AFSFid *) cbfMemp;
606     cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
607
608     /* next, we must iterate over the directory, starting from the specified
609      * cookie offset (dirCookie), and counting out nentries file entries.
610      * We skip files that already have stat cache entries, since we
611      * dont want to bulk stat files that are already in the cache.
612      */
613   tagain:
614     code = afs_VerifyVCache(adp, areqp);
615     if (code)
616         goto done2;
617
618     dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
619     if (!dcp) {
620         code = ENOENT;
621         goto done2;
622     }
623
624     /* lock the directory cache entry */
625     ObtainReadLock(&adp->lock);
626     ObtainReadLock(&dcp->lock);
627
628     /*
629      * Make sure that the data in the cache is current. There are two
630      * cases we need to worry about:
631      * 1. The cache data is being fetched by another process.
632      * 2. The cache data is no longer valid
633      */
634     while ((adp->states & CStatd)
635            && (dcp->dflags & DFFetching)
636            && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
637         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
638                    __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, dcp,
639                    ICL_TYPE_INT32, dcp->dflags);
640         ReleaseReadLock(&dcp->lock);
641         ReleaseReadLock(&adp->lock);
642         afs_osi_Sleep(&dcp->validPos);
643         ObtainReadLock(&adp->lock);
644         ObtainReadLock(&dcp->lock);
645     }
646     if (!(adp->states & CStatd)
647         || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
648         ReleaseReadLock(&dcp->lock);
649         ReleaseReadLock(&adp->lock);
650         afs_PutDCache(dcp);
651         goto tagain;
652     }
653
654     /* Generate a sequence number so we can tell whether we should
655      * store the attributes when processing the response. This number is
656      * stored in the file size when we set the CBulkFetching bit. If the
657      * CBulkFetching is still set and this value hasn't changed, then
658      * we know we were the last to set CBulkFetching bit for this file,
659      * and it is safe to set the status information for this file.
660      */
661     statSeqNo = bulkStatCounter++;
662
663     /* now we have dir data in the cache, so scan the dir page */
664     fidIndex = 0;
665     flagIndex = 0;
666     while (1) {                 /* Should probably have some constant bound */
667         /* look for first safe entry to examine in the directory.  BlobScan
668          * looks for a the 1st allocated dir after the dirCookie slot.
669          */
670         newIndex = BlobScan(dcp, (dirCookie >> 5));
671         if (newIndex == 0)
672             break;
673
674         /* remember the updated directory cookie */
675         dirCookie = newIndex << 5;
676
677         /* get a ptr to the dir entry */
678         dirEntryp =
679             (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
680         if (!dirEntryp)
681             break;
682
683         /* dont copy more than we have room for */
684         if (fidIndex >= nentries) {
685             DRelease((struct buffer *)dirEntryp, 0);
686             break;
687         }
688
689         /* now, if the dir entry looks good, copy it out to our list.  Vnode
690          * 0 means deleted, although it should also be free were it deleted.
691          */
692         if (dirEntryp->fid.vnode != 0) {
693             /* dont copy entries we have in our cache.  This check will
694              * also make us skip "." and probably "..", unless it has
695              * disappeared from the cache since we did our namei call.
696              */
697             tfid.Cell = adp->fid.Cell;
698             tfid.Fid.Volume = adp->fid.Fid.Volume;
699             tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
700             tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
701             do {
702                 retry = 0;
703                 ObtainWriteLock(&afs_xvcache, 130);
704                 tvcp = afs_FindVCache(&tfid, &retry, IS_WLOCK /* no stats | LRU */ );
705                 if (tvcp && retry) {
706                     ReleaseWriteLock(&afs_xvcache);
707                     afs_PutVCache(tvcp);
708                 }
709             } while (tvcp && retry);
710             if (!tvcp) {        /* otherwise, create manually */
711                 tvcp = afs_NewVCache(&tfid, hostp);
712                 if (tvcp)
713                 {
714                         ObtainWriteLock(&tvcp->lock, 505);
715                         ReleaseWriteLock(&afs_xvcache);
716                         afs_RemoveVCB(&tfid);
717                         ReleaseWriteLock(&tvcp->lock);
718                 } else {
719                         ReleaseWriteLock(&afs_xvcache);
720                 }
721             } else {
722                 ReleaseWriteLock(&afs_xvcache);
723             }
724             if (!tvcp)
725             {
726                 DRelease((struct buffer *)dirEntryp, 0);
727                 ReleaseReadLock(&dcp->lock);
728                 ReleaseReadLock(&adp->lock);
729                 afs_PutDCache(dcp);
730                 goto done;      /* can happen if afs_NewVCache fails */
731             }
732
733 #ifdef AFS_DARWIN80_ENV
734             if (tvcp->states & CVInit) {
735                  /* XXX don't have status yet, so creating the vnode is
736                     not yet useful. we would get CDeadVnode set, and the
737                     upcoming PutVCache will cause the vcache to be flushed &
738                     freed, which in turn means the bulkstatus results won't 
739                     be used */
740             }
741 #endif
742             /* WARNING: afs_DoBulkStat uses the Length field to store a
743              * sequence number for each bulk status request. Under no
744              * circumstances should afs_DoBulkStat store a sequence number
745              * if the new length will be ignored when afs_ProcessFS is
746              * called with new stats. */
747 #ifdef AFS_SGI_ENV
748             if (!(tvcp->states & (CStatd | CBulkFetching))
749                 && (tvcp->execsOrWriters <= 0)
750                 && !afs_DirtyPages(tvcp)
751                 && !AFS_VN_MAPPED((vnode_t *) tvcp))
752 #else
753             if (!(tvcp->states & (CStatd | CBulkFetching))
754                 && (tvcp->execsOrWriters <= 0)
755                 && !afs_DirtyPages(tvcp))
756 #endif
757
758             {
759                 /* this entry doesnt exist in the cache, and is not
760                  * already being fetched by someone else, so add it to the
761                  * list of file IDs to obtain.
762                  *
763                  * We detect a callback breaking race condition by checking the
764                  * CBulkFetching state bit and the value in the file size.
765                  * It is safe to set the status only if the CBulkFetching
766                  * flag is still set and the value in the file size does
767                  * not change.
768                  *
769                  * Don't fetch status for dirty files. We need to
770                  * preserve the value of the file size. We could
771                  * flush the pages, but it wouldn't be worthwhile.
772                  */
773                 memcpy((char *)(fidsp + fidIndex), (char *)&tfid.Fid,
774                        sizeof(*fidsp));
775                 tvcp->states |= CBulkFetching;
776                 tvcp->m.Length = statSeqNo;
777                 fidIndex++;
778             }
779             afs_PutVCache(tvcp);
780         }
781
782         /* if dir vnode has non-zero entry */
783         /* move to the next dir entry by adding in the # of entries
784          * used by this dir entry.
785          */
786         temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
787         DRelease((struct buffer *)dirEntryp, 0);
788         if (temp <= 0)
789             break;
790         dirCookie += temp;
791     }                           /* while loop over all dir entries */
792
793     /* now release the dir lock and prepare to make the bulk RPC */
794     ReleaseReadLock(&dcp->lock);
795     ReleaseReadLock(&adp->lock);
796
797     /* release the chunk */
798     afs_PutDCache(dcp);
799
800     /* dont make a null call */
801     if (fidIndex == 0)
802         goto done;
803
804     do {
805         /* setup the RPC parm structures */
806         fidParm.AFSCBFids_len = fidIndex;
807         fidParm.AFSCBFids_val = fidsp;
808         statParm.AFSBulkStats_len = fidIndex;
809         statParm.AFSBulkStats_val = statsp;
810         cbParm.AFSCBs_len = fidIndex;
811         cbParm.AFSCBs_val = cbsp;
812
813         /* start the timer; callback expirations are relative to this */
814         startTime = osi_Time();
815
816         tcp = afs_Conn(&adp->fid, areqp, SHARED_LOCK);
817         if (tcp) {
818             hostp = tcp->srvr->server;
819             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
820             RX_AFS_GUNLOCK();
821
822             if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
823                 code =
824                     RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
825                                            &cbParm, &volSync);
826                 if (code == RXGEN_OPCODE) {
827                     tcp->srvr->server->flags |= SNO_INLINEBULK;
828                     inlinebulk = 0;
829                     code =
830                         RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
831                                          &cbParm, &volSync);
832                 } else
833                     inlinebulk = 1;
834             } else {
835                 inlinebulk = 0;
836                 code =
837                     RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
838                                      &volSync);
839             }
840             RX_AFS_GLOCK();
841             XSTATS_END_TIME;
842         } else
843             code = -1;
844     } while (afs_Analyze
845              (tcp, code, &adp->fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
846               SHARED_LOCK, NULL));
847
848     /* now, if we didnt get the info, bail out. */
849     if (code)
850         goto done;
851
852     /* we need vol flags to create the entries properly */
853     dotdot.Fid.Volume = 0;
854     volp = afs_GetVolume(&adp->fid, areqp, READ_LOCK);
855     if (volp) {
856         volStates = volp->states;
857         if (volp->dotdot.Fid.Volume != 0)
858             dotdot = volp->dotdot;
859     } else
860         volStates = 0;
861
862     /* find the place to merge the info into  We do this by skipping
863      * nskip entries in the LRU queue.  The more we skip, the more
864      * we preserve, since the head of the VLRU queue is the most recently
865      * referenced file.
866      */
867   reskip:
868     nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
869     ObtainReadLock(&afs_xvcache);
870     if (QEmpty(&VLRU)) {
871         /* actually a serious error, probably should panic. Probably will 
872          * panic soon, oh well. */
873         ReleaseReadLock(&afs_xvcache);
874         afs_warnuser("afs_DoBulkStat: VLRU empty!");
875         goto done;
876     }
877     if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
878         refpanic("Bulkstat VLRU inconsistent");
879     }
880     for (tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
881         if (--nskip <= 0)
882             break;
883         else if (QNext(QPrev(tq)) != tq) {
884             BStvc = QTOV(tq);
885             refpanic("BulkStat VLRU inconsistent");
886         }
887     }
888     if (tq != &VLRU)
889         lruvcp = QTOV(tq);
890     else
891         lruvcp = QTOV(VLRU.next);
892
893     /* now we have to hold this entry, so that it does not get moved
894      * into the free list while we're running.  It could still get
895      * moved within the lru queue, but hopefully that will be rare; it
896      * doesn't hurt nearly as much.
897      */
898     retry = 0;
899     osi_vnhold(lruvcp, &retry);
900     ReleaseReadLock(&afs_xvcache);      /* could be read lock */
901     if (retry)
902         goto reskip;
903
904     /* otherwise, merge in the info.  We have to be quite careful here,
905      * since we need to ensure that we don't merge old info over newer
906      * stuff in a stat cache entry.  We're very conservative here: we don't
907      * do the merge at all unless we ourselves create the stat cache
908      * entry.  That's pretty safe, and should work pretty well, since we
909      * typically expect to do the stat cache creation ourselves.
910      *
911      * We also have to take into account racing token revocations.
912      */
913     for (i = 0; i < fidIndex; i++) {
914         if ((&statsp[i])->errorCode)
915             continue;
916         afid.Cell = adp->fid.Cell;
917         afid.Fid.Volume = adp->fid.Fid.Volume;
918         afid.Fid.Vnode = fidsp[i].Vnode;
919         afid.Fid.Unique = fidsp[i].Unique;
920         do {
921             retry = 0;
922             ObtainReadLock(&afs_xvcache);
923             tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
924             ReleaseReadLock(&afs_xvcache);
925         } while (tvcp && retry);
926
927         /* The entry may no longer exist */
928         if (tvcp == NULL) {
929             continue;
930         }
931
932         /* now we have the entry held, but we need to fill it in */
933         ObtainWriteLock(&tvcp->lock, 131);
934
935         /* if CBulkFetching is not set, or if the file size no longer
936          * matches the value we placed there when we set the CBulkFetching
937          * flag, then someone else has done something with this node,
938          * and we may not have the latest status information for this
939          * file.  Leave the entry alone.
940          */
941         if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
942             flagIndex++;
943             ReleaseWriteLock(&tvcp->lock);
944             afs_PutVCache(tvcp);
945             continue;
946         }
947
948         /* now copy ".." entry back out of volume structure, if necessary */
949         if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
950             if (!tvcp->mvid)
951                 tvcp->mvid = (struct VenusFid *)
952                     osi_AllocSmallSpace(sizeof(struct VenusFid));
953             *tvcp->mvid = dotdot;
954         }
955
956         ObtainWriteLock(&afs_xvcache, 132);
957         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
958             refpanic("Bulkstat VLRU inconsistent2");
959         }
960         if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
961             || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
962             refpanic("Bulkstat VLRU inconsistent4");
963         }
964         if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
965             || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
966             refpanic("Bulkstat VLRU inconsistent5");
967         }
968
969         if (tvcp != lruvcp) {   /* if they are == don't move it, don't corrupt vlru */
970             QRemove(&tvcp->vlruq);
971             QAdd(&lruvcp->vlruq, &tvcp->vlruq);
972         }
973
974         if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
975             refpanic("Bulkstat VLRU inconsistent3");
976         }
977         if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
978             || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
979             refpanic("Bulkstat VLRU inconsistent5");
980         }
981         if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
982             || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
983             refpanic("Bulkstat VLRU inconsistent6");
984         }
985         ReleaseWriteLock(&afs_xvcache);
986
987         ObtainWriteLock(&afs_xcbhash, 494);
988
989         /* We need to check the flags again. We may have missed
990          * something while we were waiting for a lock.
991          */
992         if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
993             flagIndex++;
994             ReleaseWriteLock(&tvcp->lock);
995             ReleaseWriteLock(&afs_xcbhash);
996             afs_PutVCache(tvcp);
997             continue;
998         }
999
1000         /* now merge in the resulting status back into the vnode.
1001          * We only do this if the entry looks clear.
1002          */
1003         afs_ProcessFS(tvcp, &statsp[i], areqp);
1004 #if defined(AFS_LINUX22_ENV)
1005         afs_fill_inode(AFSTOV(tvcp), NULL);     /* reset inode operations */
1006 #endif
1007
1008         /* do some accounting for bulk stats: mark this entry as
1009          * loaded, so we can tell if we use it before it gets
1010          * recycled.
1011          */
1012         tvcp->states |= CBulkStat;
1013         tvcp->states &= ~CBulkFetching;
1014         flagIndex++;
1015         afs_bulkStatsDone++;
1016
1017         /* merge in vol info */
1018         if (volStates & VRO)
1019             tvcp->states |= CRO;
1020         if (volStates & VBackup)
1021             tvcp->states |= CBackup;
1022         if (volStates & VForeign)
1023             tvcp->states |= CForeign;
1024
1025         /* merge in the callback info */
1026         tvcp->states |= CTruth;
1027
1028         /* get ptr to the callback we are interested in */
1029         tcbp = cbsp + i;
1030
1031         if (tcbp->ExpirationTime != 0) {
1032             tvcp->cbExpires = tcbp->ExpirationTime + startTime;
1033             tvcp->callback = hostp;
1034             tvcp->states |= CStatd;
1035             afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
1036         } else if (tvcp->states & CRO) {
1037             /* ordinary callback on a read-only volume -- AFS 3.2 style */
1038             tvcp->cbExpires = 3600 + startTime;
1039             tvcp->callback = hostp;
1040             tvcp->states |= CStatd;
1041             afs_QueueCallback(tvcp, CBHash(3600), volp);
1042         } else {
1043             tvcp->callback = 0;
1044             tvcp->states &= ~(CStatd | CUnique);
1045             afs_DequeueCallback(tvcp);
1046             if ((tvcp->states & CForeign) || (vType(tvcp) == VDIR))
1047                 osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */
1048         }
1049         ReleaseWriteLock(&afs_xcbhash);
1050
1051         ReleaseWriteLock(&tvcp->lock);
1052         /* finally, we're done with the entry */
1053         afs_PutVCache(tvcp);
1054     }                           /* for all files we got back */
1055
1056     /* finally return the pointer into the LRU queue */
1057     afs_PutVCache(lruvcp);
1058
1059   done:
1060     /* Be sure to turn off the CBulkFetching flags */
1061     for (i = flagIndex; i < fidIndex; i++) {
1062         afid.Cell = adp->fid.Cell;
1063         afid.Fid.Volume = adp->fid.Fid.Volume;
1064         afid.Fid.Vnode = fidsp[i].Vnode;
1065         afid.Fid.Unique = fidsp[i].Unique;
1066         do {
1067             retry = 0;
1068             ObtainReadLock(&afs_xvcache);
1069             tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1070             ReleaseReadLock(&afs_xvcache);
1071         } while (tvcp && retry);
1072         if (tvcp != NULL && (tvcp->states & CBulkFetching)
1073             && (tvcp->m.Length == statSeqNo)) {
1074             tvcp->states &= ~CBulkFetching;
1075         }
1076         if (tvcp != NULL) {
1077             afs_PutVCache(tvcp);
1078         }
1079     }
1080     if (volp)
1081         afs_PutVolume(volp, READ_LOCK);
1082
1083     /* If we did the InlineBulk RPC pull out the return code */
1084     if (inlinebulk) {
1085         if ((&statsp[0])->errorCode) {
1086             afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->fid, areqp,
1087                         AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL);
1088             code = (&statsp[0])->errorCode;
1089         }
1090     } else {
1091         code = 0;
1092     }
1093   done2:
1094     osi_FreeLargeSpace(statMemp);
1095     osi_FreeLargeSpace(cbfMemp);
1096     return code;
1097 }
1098
1099 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
1100 #ifdef AFS_DARWIN80_ENV
1101 #define AFSDOBULK 0
1102 #else
1103 static int AFSDOBULK = 1;
1104 #endif
1105
1106 int
1107 #ifdef AFS_OSF_ENV
1108 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int opflag, int wantparent)
1109 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
1110 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct pathname *pnp, int flags, struct vnode *rdir, struct AFS_UCRED *acred)
1111 #elif defined(UKERNEL)
1112 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int flags)
1113 #else
1114 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred)
1115 #endif
1116 {
1117     struct vrequest treq;
1118     char *tname = NULL;
1119     register struct vcache *tvc = 0;
1120     register afs_int32 code;
1121     register afs_int32 bulkcode = 0;
1122     int pass = 0, hit = 0;
1123     long dirCookie;
1124     extern afs_int32 afs_mariner;       /*Writing activity to log? */
1125     afs_hyper_t versionNo;
1126     int no_read_access = 0;
1127     struct sysname_info sysState;       /* used only for @sys checking */
1128     int dynrootRetry = 1;
1129     struct afs_fakestat_state fakestate;
1130     int tryEvalOnly = 0;
1131     OSI_VC_CONVERT(adp);
1132
1133     AFS_STATCNT(afs_lookup);
1134     afs_InitFakeStat(&fakestate);
1135
1136     if ((code = afs_InitReq(&treq, acred)))
1137         goto done;
1138
1139 #ifdef  AFS_OSF_ENV
1140     ndp->ni_dvp = AFSTOV(adp);
1141 #endif /* AFS_OSF_ENV */
1142
1143 #if defined(AFS_DARWIN_ENV)
1144     /* Workaround for MacOSX Finder, which tries to look for
1145      * .DS_Store and Contents under every directory.
1146      */
1147     if (afs_fakestat_enable && adp->mvstat == 1) {
1148         if (strcmp(aname, ".DS_Store") == 0)
1149             tryEvalOnly = 1;
1150         if (strcmp(aname, "Contents") == 0)
1151             tryEvalOnly = 1;
1152     }
1153 #endif
1154
1155     if (tryEvalOnly)
1156         code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
1157     else
1158         code = afs_EvalFakeStat(&adp, &fakestate, &treq);
1159     if (tryEvalOnly && adp->mvstat == 1)
1160         code = ENOENT;
1161     if (code)
1162         goto done;
1163
1164     *avcp = NULL;               /* Since some callers don't initialize it */
1165
1166     /* come back to here if we encounter a non-existent object in a read-only
1167      * volume's directory */
1168
1169   redo:
1170     *avcp = NULL;               /* Since some callers don't initialize it */
1171     bulkcode = 0;
1172
1173     if (!(adp->states & CStatd)) {
1174         if ((code = afs_VerifyVCache2(adp, &treq))) {
1175             goto done;
1176         }
1177     } else
1178         code = 0;
1179
1180     /* watch for ".." in a volume root */
1181     if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1182         /* looking up ".." in root via special hacks */
1183         if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
1184 #ifdef  AFS_OSF_ENV
1185             extern struct vcache *afs_globalVp;
1186             if (adp == afs_globalVp) {
1187                 struct vnode *rvp = AFSTOV(adp);
1188 /*
1189                 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
1190                 ndp->ni_dvp = ndp->ni_vp;
1191                 VN_HOLD(*avcp);
1192 */
1193                 code = ENODEV;
1194                 goto done;
1195             }
1196 #endif
1197             code = ENODEV;
1198             goto done;
1199         }
1200         /* otherwise we have the fid here, so we use it */
1201         tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
1202         afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
1203                    ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
1204         *avcp = tvc;
1205         code = (tvc ? 0 : ENOENT);
1206         hit = 1;
1207         if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1208             osi_Panic("TT1");
1209         }
1210         if (code) {
1211             /*printf("LOOKUP GETVCDOTDOT -> %d\n", code); */
1212         }
1213         goto done;
1214     }
1215
1216     /* now check the access */
1217     if (treq.uid != adp->last_looker) {
1218         if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1219             *avcp = NULL;
1220             code = EACCES;
1221             goto done;
1222         } else
1223             adp->last_looker = treq.uid;
1224     }
1225
1226     /* Check for read access as well.  We need read access in order to
1227      * stat files, but not to stat subdirectories. */
1228     if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
1229         no_read_access = 1;
1230
1231     /* special case lookup of ".".  Can we check for it sooner in this code,
1232      * for instance, way up before "redo:" ??
1233      * I'm not fiddling with the LRUQ here, either, perhaps I should, or else 
1234      * invent a lightweight version of GetVCache.
1235      */
1236     if (aname[0] == '.' && !aname[1]) { /* special case */
1237         ObtainReadLock(&afs_xvcache);
1238         osi_vnhold(adp, 0);
1239         ReleaseReadLock(&afs_xvcache);
1240 #ifdef AFS_DARWIN80_ENV
1241         vnode_get(AFSTOV(adp));
1242 #endif
1243         code = 0;
1244         *avcp = tvc = adp;
1245         hit = 1;
1246         if (adp && !VREFCOUNT_GT(adp, 0)) {
1247             osi_Panic("TT2");
1248         }
1249         goto done;
1250     }
1251
1252     Check_AtSys(adp, aname, &sysState, &treq);
1253     tname = sysState.name;
1254
1255     /* 1st Check_AtSys and lookup by tname is required here, for now,
1256      * because the dnlc is *not* told to remove entries for the parent
1257      * dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1258      * if the cached entry for the parent dir is invalidated for a
1259      * non-local change.
1260      * Otherwise, we'd be able to do a dnlc lookup on an entry ending
1261      * w/@sys and know the dnlc was consistent with reality. */
1262     tvc = osi_dnlc_lookup(adp, tname, WRITE_LOCK);
1263     *avcp = tvc;                /* maybe wasn't initialized, but it is now */
1264     if (tvc) {
1265         if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1266             /* need read access on dir to stat non-directory / non-link */
1267             afs_PutVCache(tvc);
1268             *avcp = NULL;
1269             code = EACCES;
1270             goto done;
1271         }
1272 #ifdef AFS_LINUX22_ENV
1273         if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1274             AFS_RELE(AFSTOV(tvc));
1275             *avcp = 0;
1276         } else {
1277             code = 0;
1278             hit = 1;
1279             goto done;
1280         }
1281 #else /* non - LINUX */
1282         code = 0;
1283         hit = 1;
1284         goto done;
1285 #endif /* linux22 */
1286     }
1287
1288     {                           /* sub-block just to reduce stack usage */
1289         register struct dcache *tdc;
1290         afs_size_t dirOffset, dirLen;
1291         struct VenusFid tfid;
1292
1293         /* now we have to lookup the next fid */
1294         tdc =
1295             afs_GetDCache(adp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
1296         if (!tdc) {
1297             *avcp = NULL;       /* redundant, but harmless */
1298             code = EIO;
1299             goto done;
1300         }
1301
1302         /* now we will just call dir package with appropriate inode.
1303          * Dirs are always fetched in their entirety for now */
1304         ObtainReadLock(&adp->lock);
1305         ObtainReadLock(&tdc->lock);
1306
1307         /*
1308          * Make sure that the data in the cache is current. There are two
1309          * cases we need to worry about:
1310          * 1. The cache data is being fetched by another process.
1311          * 2. The cache data is no longer valid
1312          */
1313         while ((adp->states & CStatd)
1314                && (tdc->dflags & DFFetching)
1315                && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1316             ReleaseReadLock(&tdc->lock);
1317             ReleaseReadLock(&adp->lock);
1318             afs_osi_Sleep(&tdc->validPos);
1319             ObtainReadLock(&adp->lock);
1320             ObtainReadLock(&tdc->lock);
1321         }
1322         if (!(adp->states & CStatd)
1323             || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1324             ReleaseReadLock(&tdc->lock);
1325             ReleaseReadLock(&adp->lock);
1326             afs_PutDCache(tdc);
1327             if (tname && tname != aname)
1328                 osi_FreeLargeSpace(tname);
1329             goto redo;
1330         }
1331
1332         /* Save the version number for when we call osi_dnlc_enter */
1333         hset(versionNo, tdc->f.versionNo);
1334
1335         /*
1336          * check for, and handle "@sys" if it's there.  We should be able
1337          * to avoid the alloc and the strcpy with a little work, but it's
1338          * not pressing.  If there aren't any remote users (ie, via the 
1339          * NFS translator), we have a slightly easier job.
1340          * the faster way to do this is to check for *aname == '@' and if 
1341          * it's there, check for @sys, otherwise, assume there's no @sys 
1342          * then, if the lookup fails, check for .*@sys...
1343          */
1344         /* above now implemented by Check_AtSys and Next_AtSys */
1345
1346         /* lookup the name in the appropriate dir, and return a cache entry
1347          * on the resulting fid */
1348         code =
1349             afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1350                                  &dirCookie);
1351
1352         /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1353         while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
1354             code =
1355                 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1356                                      &dirCookie);
1357         tname = sysState.name;
1358
1359         ReleaseReadLock(&tdc->lock);
1360         afs_PutDCache(tdc);
1361
1362         if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1363             ReleaseReadLock(&adp->lock);
1364             dynrootRetry = 0;
1365             if (tname[0] == '.')
1366                 afs_LookupAFSDB(tname + 1);
1367             else
1368                 afs_LookupAFSDB(tname);
1369             if (tname && tname != aname)
1370                 osi_FreeLargeSpace(tname);
1371             goto redo;
1372         } else {
1373             ReleaseReadLock(&adp->lock);
1374         }
1375
1376         /* new fid has same cell and volume */
1377         tfid.Cell = adp->fid.Cell;
1378         tfid.Fid.Volume = adp->fid.Fid.Volume;
1379         afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1380                    ICL_TYPE_STRING, tname, ICL_TYPE_FID, &tfid,
1381                    ICL_TYPE_INT32, code);
1382
1383         if (code) {
1384             if (code != ENOENT) {
1385                 printf("LOOKUP dirLookupOff -> %d\n", code);
1386             }
1387             goto done;
1388         }
1389
1390         /* prefetch some entries, if the dir is currently open.  The variable
1391          * dirCookie tells us where to start prefetching from.
1392          */
1393         if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)
1394             && !afs_IsDynroot(adp)) {
1395             afs_int32 retry;
1396             /* if the entry is not in the cache, or is in the cache,
1397              * but hasn't been statd, then do a bulk stat operation.
1398              */
1399             do {
1400                 retry = 0;
1401                 ObtainReadLock(&afs_xvcache);
1402                 tvc = afs_FindVCache(&tfid, &retry, 0 /* !stats,!lru */ );
1403                 ReleaseReadLock(&afs_xvcache);
1404             } while (tvc && retry);
1405
1406             if (!tvc || !(tvc->states & CStatd))
1407                 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1408             else
1409                 bulkcode = 0;
1410
1411             /* if the vcache isn't usable, release it */
1412             if (tvc && !(tvc->states & CStatd)) {
1413                 afs_PutVCache(tvc);
1414                 tvc = NULL;
1415             }
1416         } else {
1417             tvc = NULL;
1418             bulkcode = 0;
1419         }
1420
1421         /* now get the status info, if we don't already have it */
1422         /* This is kind of weird, but we might wind up accidentally calling
1423          * RXAFS_Lookup because we happened upon a file which legitimately
1424          * has a 0 uniquifier. That is the result of allowing unique to wrap
1425          * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1426          * the file has not yet been looked up.
1427          */
1428         if (!tvc) {
1429             afs_int32 cached = 0;
1430             if (!tfid.Fid.Unique && (adp->states & CForeign)) {
1431                 tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
1432             }
1433             if (!tvc && !bulkcode) {    /* lookup failed or wasn't called */
1434                 tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
1435             }
1436         }                       /* if !tvc */
1437     }                           /* sub-block just to reduce stack usage */
1438
1439     if (tvc) {
1440         int force_eval = afs_fakestat_enable ? 0 : 1;
1441
1442         if (adp->states & CForeign)
1443             tvc->states |= CForeign;
1444         tvc->parentVnode = adp->fid.Fid.Vnode;
1445         tvc->parentUnique = adp->fid.Fid.Unique;
1446         tvc->states &= ~CBulkStat;
1447
1448         if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
1449             ObtainSharedLock(&tvc->lock, 680);
1450             if (!tvc->linkData) {
1451                 UpgradeSToWLock(&tvc->lock, 681);
1452                 code = afs_HandleLink(tvc, &treq);
1453                 ConvertWToRLock(&tvc->lock);
1454             } else {
1455                 ConvertSToRLock(&tvc->lock);
1456                 code = 0;
1457             }
1458             if (!code && !afs_strchr(tvc->linkData, ':'))
1459                 force_eval = 1;
1460             ReleaseReadLock(&tvc->lock);
1461         }
1462 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1463         if (!(flags & AFS_LOOKUP_NOEVAL))
1464             /* don't eval mount points */
1465 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1466             if (tvc->mvstat == 1 && force_eval) {
1467                 /* a mt point, possibly unevaluated */
1468                 struct volume *tvolp;
1469
1470                 ObtainWriteLock(&tvc->lock, 133);
1471                 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1472                 ReleaseWriteLock(&tvc->lock);
1473
1474                 if (code) {
1475                     afs_PutVCache(tvc);
1476                     if (tvolp)
1477                         afs_PutVolume(tvolp, WRITE_LOCK);
1478                     goto done;
1479                 }
1480
1481                 /* next, we want to continue using the target of the mt point */
1482                 if (tvc->mvid && (tvc->states & CMValid)) {
1483                     struct vcache *uvc;
1484                     /* now lookup target, to set .. pointer */
1485                     afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1486                                ICL_TYPE_POINTER, tvc, ICL_TYPE_FID,
1487                                &tvc->fid);
1488                     uvc = tvc;  /* remember for later */
1489
1490                     if (tvolp && (tvolp->states & VForeign)) {
1491                         /* XXXX tvolp has ref cnt on but not locked! XXX */
1492                         tvc =
1493                             afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
1494                     } else {
1495                         tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
1496                     }
1497                     afs_PutVCache(uvc); /* we're done with it */
1498
1499                     if (!tvc) {
1500                         code = ENOENT;
1501                         if (tvolp) {
1502                             afs_PutVolume(tvolp, WRITE_LOCK);
1503                         }
1504                         goto done;
1505                     }
1506
1507                     /* now, if we came via a new mt pt (say because of a new
1508                      * release of a R/O volume), we must reevaluate the ..
1509                      * ptr to point back to the appropriate place */
1510                     if (tvolp) {
1511                         ObtainWriteLock(&tvc->lock, 134);
1512                         if (tvc->mvid == NULL) {
1513                             tvc->mvid = (struct VenusFid *)
1514                                 osi_AllocSmallSpace(sizeof(struct VenusFid));
1515                         }
1516                         /* setup backpointer */
1517                         *tvc->mvid = tvolp->dotdot;
1518                         ReleaseWriteLock(&tvc->lock);
1519                         afs_PutVolume(tvolp, WRITE_LOCK);
1520                     }
1521                 } else {
1522                     afs_PutVCache(tvc);
1523                     code = ENOENT;
1524                     if (tvolp)
1525                         afs_PutVolume(tvolp, WRITE_LOCK);
1526                     goto done;
1527                 }
1528             }
1529         *avcp = tvc;
1530         if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1531             osi_Panic("TT3");
1532         }
1533         code = 0;
1534     } else {
1535         /* if we get here, we found something in a directory that couldn't
1536          * be located (a Multics "connection failure").  If the volume is
1537          * read-only, we try flushing this entry from the cache and trying
1538          * again. */
1539         if (pass == 0) {
1540             struct volume *tv;
1541             tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
1542             if (tv) {
1543                 if (tv->states & VRO) {
1544                     pass = 1;   /* try this *once* */
1545                     ObtainWriteLock(&afs_xcbhash, 495);
1546                     afs_DequeueCallback(adp);
1547                     /* re-stat to get later version */
1548                     adp->states &= ~CStatd;
1549                     ReleaseWriteLock(&afs_xcbhash);
1550                     osi_dnlc_purgedp(adp);
1551                     afs_PutVolume(tv, READ_LOCK);
1552                     goto redo;
1553                 }
1554                 afs_PutVolume(tv, READ_LOCK);
1555             }
1556         }
1557         code = ENOENT;
1558     }
1559
1560   done:
1561     /* put the network buffer back, if need be */
1562     if (tname != aname && tname)
1563         osi_FreeLargeSpace(tname);
1564     if (code == 0) {
1565 #ifdef  AFS_OSF_ENV
1566         /* Handle RENAME; only need to check rename "."  */
1567         if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1568             if (!FidCmp(&(tvc->fid), &(adp->fid))) {
1569                 afs_PutVCache(*avcp);
1570                 *avcp = NULL;
1571                 afs_PutFakeStat(&fakestate);
1572                 return afs_CheckCode(EISDIR, &treq, 18);
1573             }
1574         }
1575 #endif /* AFS_OSF_ENV */
1576
1577         if (afs_mariner)
1578             afs_AddMarinerName(aname, tvc);
1579
1580 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1581         if (!(flags & AFS_LOOKUP_NOEVAL))
1582             /* Here we don't enter the name into the DNLC because we want the
1583              * evaluated mount dir to be there (the vcache for the mounted volume)
1584              * rather than the vc of the mount point itself.  we can still find the
1585              * mount point's vc in the vcache by its fid. */
1586 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1587             if (!hit) {
1588                 osi_dnlc_enter(adp, aname, tvc, &versionNo);
1589             } else {
1590 #ifdef AFS_LINUX20_ENV
1591                 /* So Linux inode cache is up to date. */
1592                 code = afs_VerifyVCache(tvc, &treq);
1593 #else
1594                 afs_PutFakeStat(&fakestate);
1595                 return 0;       /* can't have been any errors if hit and !code */
1596 #endif
1597             }
1598     }
1599     if (bulkcode)
1600         code = bulkcode;
1601
1602     code = afs_CheckCode(code, &treq, 19);
1603     if (code) {
1604         /* If there is an error, make sure *avcp is null.
1605          * Alphas panic otherwise - defect 10719.
1606          */
1607         *avcp = NULL;
1608     }
1609
1610     afs_PutFakeStat(&fakestate);
1611     return code;
1612 }