2 * Copyright 2000, International Business Machines Corporation and others.
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
17 #include <afsconfig.h>
18 #include "afs/param.h"
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 #include "afs/afs_dynroot.h"
33 extern struct DirEntry *afs_dir_GetBlob();
34 extern struct vcache *afs_globalVp;
37 afs_int32 afs_bkvolpref = 0;
38 afs_int32 afs_bulkStatsDone;
39 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
40 int afs_fakestat_enable = 0; /* 1: fakestat-all, 2: fakestat-crosscell */
43 /* this would be faster if it did comparison as int32word, but would be
44 * dependant on byte-order and alignment, and I haven't figured out
45 * what "@sys" is in binary... */
46 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
48 /* call under write lock, evaluate mvid field from a mt pt.
49 * avc is the vnode of the mount point object; must be write-locked.
50 * advc is the vnode of the containing directory (optional; if NULL and
51 * EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
52 * avolpp is where we return a pointer to the volume named by the mount pt, if success
53 * areq is the identity of the caller.
55 * NOTE: this function returns a held volume structure in *volpp if it returns 0!
58 EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
59 struct volume **avolpp, register struct vrequest *areq,
60 afs_uint32 *acellidxp, afs_uint32 *avolnump, afs_uint32 *avnoidp)
62 struct volume *tvp = 0;
65 char *cpos, *volnamep, *x;
67 afs_int32 prefetch; /* 1=>None 2=>RO 3=>BK */
68 afs_int32 mtptCell, assocCell = 0, hac = 0;
69 afs_int32 samecell, roname, len;
70 afs_uint32 volid, cellidx, vnoid = 0;
72 cpos = afs_strchr(data, ':'); /* if cell name present */
77 for (x = data; *x >= '0' && *x <= '9'; x++)
78 cellnum = (cellnum * 10) + (*x - '0');
80 tcell = afs_GetCell(cellnum, READ_LOCK);
82 tcell = afs_GetCellByName(data, READ_LOCK);
88 tcell = afs_GetCell(cellnum, READ_LOCK);
90 /*printf("No cellname %s , or cellnum %d , returning ENODEV\n",
95 /*printf("Lookup failed, returning ENODEV\n");*/
99 cellidx = tcell->cellIndex;
100 mtptCell = tcell->cellNum; /* The cell for the mountpoint */
102 hac = 1; /* has associated cell */
103 assocCell = tcell->lcellp->cellNum; /* The associated cell */
105 afs_PutCell(tcell, READ_LOCK);
107 cpos = afs_strrchr(volnamep, ':'); /* if vno present */
110 /* Look for an all-numeric volume ID */
112 for (x = volnamep; *x >= '0' && *x <= '9'; x++)
113 volid = (volid * 10) + (*x - '0');
117 if (!*x) /* allow vno with numeric volid only */
118 for (x = (cpos + 1); *x >= '0' && *x <= '9'; x++)
119 vnoid = (vnoid * 10) + (*x - '0');
125 * If the volume ID was all-numeric, and they didn't ask for a
126 * pointer to the volume structure, then just return the number
127 * as-is. This is currently only used for handling name lookups
128 * in the dynamic mount directory.
130 if (!*x && !avolpp) {
132 *acellidxp = cellidx;
141 * If the volume ID was all-numeric, and the type was '%', then
142 * assume whoever made the mount point knew what they were doing,
143 * and don't second-guess them by forcing use of a RW volume when
144 * they gave the ID of something else.
146 if (!*x && type == '%') {
147 tfid.Fid.Volume = volid; /* remember BK volume */
148 tfid.Cell = mtptCell;
149 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
151 /*printf("afs_GetVolume failed - returning ENODEV");*/
152 return ENODEV; /* oops, can't do it */
157 /* Is volume name a "<n>.backup" or "<n>.readonly" name */
158 len = strlen(volnamep);
159 roname = ((len > 9) && (strcmp(&volnamep[len - 9], ".readonly") == 0))
160 || ((len > 7) && (strcmp(&volnamep[len - 7], ".backup") == 0));
162 /* When we cross mountpoint, do we stay in the same cell */
163 samecell = (cellnum == mtptCell) || (hac && (cellnum == assocCell));
165 /* Decide whether to prefetch the BK, or RO. Also means we want the BK or
167 * If this is a regular mountpoint with a RW volume name
168 * - If BK preference is enabled AND we remain within the same cell AND
169 * start from a BK volume, then we will want to prefetch the BK volume.
170 * - If we cross a cell boundary OR start from a RO volume, then we will
171 * want to prefetch the RO volume.
173 if ((type == '#') && !roname) {
174 if (afs_bkvolpref && samecell && (states & CBackup))
175 prefetch = 3; /* Prefetch the BK */
176 else if (!samecell || (states & CRO))
177 prefetch = 2; /* Prefetch the RO */
179 prefetch = 1; /* Do not prefetch */
181 prefetch = 1; /* Do not prefetch */
184 /* Get the volume struct. Unless this volume name has ".readonly" or
185 * ".backup" in it, this will get the volume struct for the RW volume.
186 * The RO volume will be prefetched if requested (but not returned).
188 /*printf("Calling GetVolumeByName\n");*/
189 tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK);
191 /* If no volume was found in this cell, try the associated linked cell */
192 if (!tvp && hac && areq->volumeError) {
194 afs_GetVolumeByName(volnamep, assocCell, prefetch, areq,
198 /* Still not found. If we are looking for the RO, then perhaps the RW
199 * doesn't exist? Try adding ".readonly" to volname and look for that.
200 * Don't know why we do this. Would have still found it in above call - jpm.
202 if (!tvp && (prefetch == 2) && len < AFS_SMALLOCSIZ - 10) {
203 buf = (char *)osi_AllocSmallSpace(len + 10);
205 strcpy(buf, volnamep);
206 afs_strcat(buf, ".readonly");
208 tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
210 /* Try the associated linked cell if failed */
211 if (!tvp && hac && areq->volumeError) {
212 tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
214 osi_FreeSmallSpace(buf);
218 /*printf("Couldn't find the volume\n");*/
219 return ENODEV; /* Couldn't find the volume */
222 /* Don't cross mountpoint from a BK to a BK volume */
223 if ((states & CBackup) && (tvp->states & VBackup)) {
224 afs_PutVolume(tvp, WRITE_LOCK);
228 /* If we want (prefetched) the BK and it exists, then drop the RW volume
230 * Otherwise, if we want (prefetched0 the RO and it exists, then drop the
231 * RW volume and get the RO.
232 * Otherwise, go with the RW.
234 if ((prefetch == 3) && tvp->backVol) {
235 tfid.Fid.Volume = tvp->backVol; /* remember BK volume */
236 tfid.Cell = tvp->cell;
237 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
238 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
240 return ENODEV; /* oops, can't do it */
241 } else if ((prefetch >= 2) && tvp->roVol) {
242 tfid.Fid.Volume = tvp->roVol; /* remember RO volume */
243 tfid.Cell = tvp->cell;
244 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
245 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
247 return ENODEV; /* oops, can't do it */
252 *acellidxp = cellidx;
254 *avolnump = tvp->volume;
260 afs_PutVolume(tvp, WRITE_LOCK);
265 EvalMountPoint(register struct vcache *avc, struct vcache *advc,
266 struct volume **avolpp, register struct vrequest *areq)
271 AFS_STATCNT(EvalMountPoint);
273 if (avc->mvid && (avc->states & CMValid))
274 return 0; /* done while racing */
277 code = afs_HandleLink(avc, areq);
281 /* Determine which cell and volume the mointpoint goes to */
282 code = EvalMountData(avc->linkData[0], avc->linkData + 1,
283 avc->states, avc->fid.Cell, avolpp, areq, 0, 0,
285 if (code) return code;
292 (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
293 avc->mvid->Cell = (*avolpp)->cell;
294 avc->mvid->Fid.Volume = (*avolpp)->volume;
295 avc->mvid->Fid.Vnode = avnoid;
296 avc->mvid->Fid.Unique = 1;
297 avc->states |= CMValid;
299 /* Used to: if the mount point is stored within a backup volume,
300 * then we should only update the parent pointer information if
301 * there's none already set, so as to avoid updating a volume's ..
302 * info with something in an OldFiles directory.
304 * Next two lines used to be under this if:
306 * if (!(avc->states & CBackup) || tvp->dotdot.Fid.Volume == 0)
308 * Now: update mount point back pointer on every call, so that we handle
309 * multiple mount points better. This way, when du tries to go back
310 * via chddir(".."), it will end up exactly where it started, yet
311 * cd'ing via a new path to a volume will reset the ".." pointer
314 (*avolpp)->mtpoint = avc->fid; /* setup back pointer to mtpoint */
316 (*avolpp)->dotdot = advc->fid;
324 * Must be called on an afs_fakestat_state object before calling
325 * afs_EvalFakeStat or afs_PutFakeStat. Calling afs_PutFakeStat
326 * without calling afs_EvalFakeStat is legal, as long as this
327 * function is called.
330 afs_InitFakeStat(struct afs_fakestat_state *state)
332 if (!afs_fakestat_enable)
337 state->need_release = 0;
341 * afs_EvalFakeStat_int
343 * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
344 * which is called by those wrapper functions.
346 * Only issues RPCs if canblock is non-zero.
349 afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
350 struct vrequest *areq, int canblock)
352 struct vcache *tvc, *root_vp;
353 struct volume *tvolp = NULL;
356 if (!afs_fakestat_enable)
359 osi_Assert(state->valid == 1);
360 osi_Assert(state->did_eval == 0);
364 if (tvc->mvstat != 1)
367 /* Is the call to VerifyVCache really necessary? */
368 code = afs_VerifyVCache(tvc, areq);
372 ObtainWriteLock(&tvc->lock, 599);
373 code = EvalMountPoint(tvc, NULL, &tvolp, areq);
374 ReleaseWriteLock(&tvc->lock);
378 tvolp->dotdot = tvc->fid;
379 tvolp->dotdot.Fid.Vnode = tvc->parentVnode;
380 tvolp->dotdot.Fid.Unique = tvc->parentUnique;
383 if (tvc->mvid && (tvc->states & CMValid)) {
389 ObtainWriteLock(&afs_xvcache, 597);
390 root_vp = afs_FindVCache(tvc->mvid, &retry, IS_WLOCK);
391 if (root_vp && retry) {
392 ReleaseWriteLock(&afs_xvcache);
393 afs_PutVCache(root_vp);
395 } while (root_vp && retry);
396 ReleaseWriteLock(&afs_xvcache);
398 root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
401 code = canblock ? ENOENT : 0;
404 #ifdef AFS_DARWIN80_ENV
405 root_vp->m.Type = VDIR;
407 code = afs_darwin_finalizevnode(root_vp, NULL, NULL, 0);
410 vnode_ref(AFSTOV(root_vp));
412 if (tvolp && !afs_InReadDir(root_vp)) {
413 /* Is this always kosher? Perhaps we should instead use
414 * NBObtainWriteLock to avoid potential deadlock.
416 ObtainWriteLock(&root_vp->lock, 598);
418 root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
419 *root_vp->mvid = tvolp->dotdot;
420 ReleaseWriteLock(&root_vp->lock);
422 state->need_release = 1;
423 state->root_vp = root_vp;
427 code = canblock ? ENOENT : 0;
432 afs_PutVolume(tvolp, WRITE_LOCK);
439 * Automatically does the equivalent of EvalMountPoint for vcache entries
440 * which are mount points. Remembers enough state to properly release
441 * the volume root vcache when afs_PutFakeStat() is called.
443 * State variable must be initialized by afs_InitFakeState() beforehand.
445 * Returns 0 when everything succeeds and *avcp points to the vcache entry
446 * that should be used for the real vnode operation. Returns non-zero if
447 * something goes wrong and the error code should be returned to the user.
450 afs_EvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
451 struct vrequest *areq)
453 return afs_EvalFakeStat_int(avcp, state, areq, 1);
457 * afs_TryEvalFakeStat
459 * Same as afs_EvalFakeStat, but tries not to talk to remote servers
460 * and only evaluate the mount point if all the data is already in
463 * Returns 0 if everything succeeds and *avcp points to a valid
464 * vcache entry (possibly evaluated).
467 afs_TryEvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
468 struct vrequest *areq)
470 return afs_EvalFakeStat_int(avcp, state, areq, 0);
476 * Perform any necessary cleanup at the end of a vnode op, given that
477 * afs_InitFakeStat was previously called with this state.
480 afs_PutFakeStat(struct afs_fakestat_state *state)
482 if (!afs_fakestat_enable)
485 osi_Assert(state->valid == 1);
486 if (state->need_release)
487 afs_PutVCache(state->root_vp);
492 afs_ENameOK(register char *aname)
496 AFS_STATCNT(ENameOK);
497 tlen = strlen(aname);
498 if (tlen >= 4 && strcmp(aname + tlen - 4, "@sys") == 0)
504 afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
505 register char *bufp, int *num, char **sysnamelist[])
507 register struct unixuser *au;
508 register afs_int32 error;
510 AFS_STATCNT(getsysname);
512 *sysnamelist = afs_sysnamelist;
514 if (!afs_nfsexporter)
515 strcpy(bufp, (*sysnamelist)[0]);
517 au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
519 error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
521 strcpy(bufp, "@sys");
525 strcpy(bufp, (*sysnamelist)[0]);
528 strcpy(bufp, afs_sysname);
535 Check_AtSys(register struct vcache *avc, const char *aname,
536 struct sysname_info *state, struct vrequest *areq)
539 char **sysnamelist[MAXNUMSYSNAMES];
541 if (AFS_EQ_ATSYS(aname)) {
543 state->name = (char *)osi_AllocLargeSpace(MAXSYSNAME);
546 afs_getsysname(areq, avc, state->name, &num, sysnamelist);
551 state->name = (char *)aname;
556 Next_AtSys(register struct vcache *avc, struct vrequest *areq,
557 struct sysname_info *state)
559 int num = afs_sysnamecount;
560 char **sysnamelist[MAXNUMSYSNAMES];
562 if (state->index == -1)
563 return 0; /* No list */
565 /* Check for the initial state of aname != "@sys" in Check_AtSys */
566 if (state->offset == -1 && state->allocked == 0) {
567 register char *tname;
569 /* Check for .*@sys */
570 for (tname = state->name; *tname; tname++)
571 /*Move to the end of the string */ ;
573 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
574 state->offset = (tname - 4) - state->name;
575 tname = (char *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
576 strncpy(tname, state->name, state->offset);
581 afs_getsysname(areq, avc, state->name + state->offset, &num,
585 return 0; /* .*@sys doesn't match either */
587 register struct unixuser *au;
588 register afs_int32 error;
590 *sysnamelist = afs_sysnamelist;
592 if (afs_nfsexporter) {
593 au = afs_GetUser(areq->uid, avc->fid.Cell, 0);
596 EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
604 if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
605 return 0; /* end of list */
607 strcpy(state->name + state->offset, (*sysnamelist)[(unsigned int)state->index]);
611 extern int BlobScan(struct dcache * afile, afs_int32 ablob);
613 /* called with an unlocked directory and directory cookie. Areqp
614 * describes who is making the call.
615 * Scans the next N (about 30, typically) directory entries, and does
616 * a bulk stat call to stat them all.
618 * Must be very careful when merging in RPC responses, since we dont
619 * want to overwrite newer info that was added by a file system mutating
620 * call that ran concurrently with our bulk stat call.
622 * We do that, as described below, by not merging in our info (always
623 * safe to skip the merge) if the status info is valid in the vcache entry.
625 * If adapt ever implements the bulk stat RPC, then this code will need to
626 * ensure that vcaches created for failed RPC's to older servers have the
629 static struct vcache *BStvc = NULL;
632 afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
634 int nentries; /* # of entries to prefetch */
635 int nskip; /* # of slots in the LRU queue to skip */
636 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
637 struct dcache *dcp; /* chunk containing the dir block */
638 char *statMemp; /* status memory block */
639 char *cbfMemp; /* callback and fid memory block */
640 afs_size_t temp; /* temp for holding chunk length, &c. */
641 struct AFSFid *fidsp; /* file IDs were collecting */
642 struct AFSCallBack *cbsp; /* call back pointers */
643 struct AFSCallBack *tcbp; /* temp callback ptr */
644 struct AFSFetchStatus *statsp; /* file status info */
645 struct AFSVolSync volSync; /* vol sync return info */
646 struct vcache *tvcp; /* temp vcp */
647 struct afs_q *tq; /* temp queue variable */
648 AFSCBFids fidParm; /* file ID parm for bulk stat */
649 AFSBulkStats statParm; /* stat info parm for bulk stat */
650 int fidIndex = 0; /* which file were stating */
651 struct conn *tcp = 0; /* conn for call */
652 AFSCBs cbParm; /* callback parm for bulk stat */
653 struct server *hostp = 0; /* host we got callback from */
654 long startTime; /* time we started the call,
655 * for callback expiration base
657 afs_size_t statSeqNo = 0; /* Valued of file size to detect races */
658 int code; /* error code */
659 long newIndex; /* new index in the dir */
660 struct DirEntry *dirEntryp; /* dir entry we are examining */
662 struct VenusFid afid; /* file ID we are using now */
663 struct VenusFid tfid; /* another temp. file ID */
664 afs_int32 retry; /* handle low-level SGI MP race conditions */
665 long volStates; /* flags from vol structure */
666 struct volume *volp = 0; /* volume ptr */
667 struct VenusFid dotdot;
668 int flagIndex = 0; /* First file with bulk fetch flag set */
669 int inlinebulk = 0; /* Did we use InlineBulk RPC or not? */
671 #ifdef AFS_DARWIN80_ENV
672 panic("bulkstatus doesn't work on AFS_DARWIN80_ENV. don't call it");
674 /* first compute some basic parameters. We dont want to prefetch more
675 * than a fraction of the cache in any given call, and we want to preserve
676 * a portion of the LRU queue in any event, so as to avoid thrashing
677 * the entire stat cache (we will at least leave some of it alone).
678 * presently dont stat more than 1/8 the cache in any one call. */
679 nentries = afs_cacheStats / 8;
681 /* dont bother prefetching more than one calls worth of info */
682 if (nentries > AFSCBMAX)
685 /* heuristic to make sure that things fit in 4K. This means that
686 * we shouldnt make it any bigger than 47 entries. I am typically
687 * going to keep it a little lower, since we don't want to load
688 * too much of the stat cache.
693 /* now, to reduce the stack size, well allocate two 4K blocks,
694 * one for fids and callbacks, and one for stat info. Well set
695 * up our pointers to the memory from there, too.
697 statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
698 statsp = (struct AFSFetchStatus *)statMemp;
700 osi_AllocLargeSpace(nentries *
701 (sizeof(AFSCallBack) + sizeof(AFSFid)));
702 fidsp = (AFSFid *) cbfMemp;
703 cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
705 /* next, we must iterate over the directory, starting from the specified
706 * cookie offset (dirCookie), and counting out nentries file entries.
707 * We skip files that already have stat cache entries, since we
708 * dont want to bulk stat files that are already in the cache.
711 code = afs_VerifyVCache(adp, areqp);
715 dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
721 /* lock the directory cache entry */
722 ObtainReadLock(&adp->lock);
723 ObtainReadLock(&dcp->lock);
726 * Make sure that the data in the cache is current. There are two
727 * cases we need to worry about:
728 * 1. The cache data is being fetched by another process.
729 * 2. The cache data is no longer valid
731 while ((adp->states & CStatd)
732 && (dcp->dflags & DFFetching)
733 && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
734 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
735 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, dcp,
736 ICL_TYPE_INT32, dcp->dflags);
737 ReleaseReadLock(&dcp->lock);
738 ReleaseReadLock(&adp->lock);
739 afs_osi_Sleep(&dcp->validPos);
740 ObtainReadLock(&adp->lock);
741 ObtainReadLock(&dcp->lock);
743 if (!(adp->states & CStatd)
744 || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
745 ReleaseReadLock(&dcp->lock);
746 ReleaseReadLock(&adp->lock);
751 /* Generate a sequence number so we can tell whether we should
752 * store the attributes when processing the response. This number is
753 * stored in the file size when we set the CBulkFetching bit. If the
754 * CBulkFetching is still set and this value hasn't changed, then
755 * we know we were the last to set CBulkFetching bit for this file,
756 * and it is safe to set the status information for this file.
758 statSeqNo = bulkStatCounter++;
760 /* now we have dir data in the cache, so scan the dir page */
763 while (1) { /* Should probably have some constant bound */
764 /* look for first safe entry to examine in the directory. BlobScan
765 * looks for a the 1st allocated dir after the dirCookie slot.
767 newIndex = BlobScan(dcp, (dirCookie >> 5));
771 /* remember the updated directory cookie */
772 dirCookie = newIndex << 5;
774 /* get a ptr to the dir entry */
776 (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
780 /* dont copy more than we have room for */
781 if (fidIndex >= nentries) {
782 DRelease((struct buffer *)dirEntryp, 0);
786 /* now, if the dir entry looks good, copy it out to our list. Vnode
787 * 0 means deleted, although it should also be free were it deleted.
789 if (dirEntryp->fid.vnode != 0) {
790 /* dont copy entries we have in our cache. This check will
791 * also make us skip "." and probably "..", unless it has
792 * disappeared from the cache since we did our namei call.
794 tfid.Cell = adp->fid.Cell;
795 tfid.Fid.Volume = adp->fid.Fid.Volume;
796 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
797 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
800 ObtainWriteLock(&afs_xvcache, 130);
801 tvcp = afs_FindVCache(&tfid, &retry, IS_WLOCK /* no stats | LRU */ );
803 ReleaseWriteLock(&afs_xvcache);
806 } while (tvcp && retry);
807 if (!tvcp) { /* otherwise, create manually */
808 tvcp = afs_NewVCache(&tfid, hostp);
811 ObtainWriteLock(&tvcp->lock, 505);
812 ReleaseWriteLock(&afs_xvcache);
813 afs_RemoveVCB(&tfid);
814 ReleaseWriteLock(&tvcp->lock);
816 ReleaseWriteLock(&afs_xvcache);
819 ReleaseWriteLock(&afs_xvcache);
823 DRelease((struct buffer *)dirEntryp, 0);
824 ReleaseReadLock(&dcp->lock);
825 ReleaseReadLock(&adp->lock);
827 goto done; /* can happen if afs_NewVCache fails */
830 #ifdef AFS_DARWIN80_ENV
831 if (tvcp->states & CVInit) {
832 /* XXX don't have status yet, so creating the vnode is
833 not yet useful. we would get CDeadVnode set, and the
834 upcoming PutVCache will cause the vcache to be flushed &
835 freed, which in turn means the bulkstatus results won't
839 /* WARNING: afs_DoBulkStat uses the Length field to store a
840 * sequence number for each bulk status request. Under no
841 * circumstances should afs_DoBulkStat store a sequence number
842 * if the new length will be ignored when afs_ProcessFS is
843 * called with new stats. */
845 if (!(tvcp->states & (CStatd | CBulkFetching))
846 && (tvcp->execsOrWriters <= 0)
847 && !afs_DirtyPages(tvcp)
848 && !AFS_VN_MAPPED((vnode_t *) tvcp))
850 if (!(tvcp->states & (CStatd | CBulkFetching))
851 && (tvcp->execsOrWriters <= 0)
852 && !afs_DirtyPages(tvcp))
856 /* this entry doesnt exist in the cache, and is not
857 * already being fetched by someone else, so add it to the
858 * list of file IDs to obtain.
860 * We detect a callback breaking race condition by checking the
861 * CBulkFetching state bit and the value in the file size.
862 * It is safe to set the status only if the CBulkFetching
863 * flag is still set and the value in the file size does
866 * Don't fetch status for dirty files. We need to
867 * preserve the value of the file size. We could
868 * flush the pages, but it wouldn't be worthwhile.
870 memcpy((char *)(fidsp + fidIndex), (char *)&tfid.Fid,
872 tvcp->states |= CBulkFetching;
873 tvcp->m.Length = statSeqNo;
879 /* if dir vnode has non-zero entry */
880 /* move to the next dir entry by adding in the # of entries
881 * used by this dir entry.
883 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
884 DRelease((struct buffer *)dirEntryp, 0);
888 } /* while loop over all dir entries */
890 /* now release the dir lock and prepare to make the bulk RPC */
891 ReleaseReadLock(&dcp->lock);
892 ReleaseReadLock(&adp->lock);
894 /* release the chunk */
897 /* dont make a null call */
902 /* setup the RPC parm structures */
903 fidParm.AFSCBFids_len = fidIndex;
904 fidParm.AFSCBFids_val = fidsp;
905 statParm.AFSBulkStats_len = fidIndex;
906 statParm.AFSBulkStats_val = statsp;
907 cbParm.AFSCBs_len = fidIndex;
908 cbParm.AFSCBs_val = cbsp;
910 /* start the timer; callback expirations are relative to this */
911 startTime = osi_Time();
913 tcp = afs_Conn(&adp->fid, areqp, SHARED_LOCK);
915 hostp = tcp->srvr->server;
916 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
919 if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
921 RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
923 if (code == RXGEN_OPCODE) {
924 tcp->srvr->server->flags |= SNO_INLINEBULK;
927 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
934 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
942 (tcp, code, &adp->fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
945 /* now, if we didnt get the info, bail out. */
949 /* we need vol flags to create the entries properly */
950 dotdot.Fid.Volume = 0;
951 volp = afs_GetVolume(&adp->fid, areqp, READ_LOCK);
953 volStates = volp->states;
954 if (volp->dotdot.Fid.Volume != 0)
955 dotdot = volp->dotdot;
959 /* find the place to merge the info into We do this by skipping
960 * nskip entries in the LRU queue. The more we skip, the more
961 * we preserve, since the head of the VLRU queue is the most recently
965 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
966 ObtainReadLock(&afs_xvcache);
968 /* actually a serious error, probably should panic. Probably will
969 * panic soon, oh well. */
970 ReleaseReadLock(&afs_xvcache);
971 afs_warnuser("afs_DoBulkStat: VLRU empty!");
974 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
975 refpanic("Bulkstat VLRU inconsistent");
977 for (tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
980 else if (QNext(QPrev(tq)) != tq) {
982 refpanic("BulkStat VLRU inconsistent");
988 lruvcp = QTOV(VLRU.next);
990 /* now we have to hold this entry, so that it does not get moved
991 * into the free list while we're running. It could still get
992 * moved within the lru queue, but hopefully that will be rare; it
993 * doesn't hurt nearly as much.
996 osi_vnhold(lruvcp, &retry);
997 ReleaseReadLock(&afs_xvcache); /* could be read lock */
1001 /* otherwise, merge in the info. We have to be quite careful here,
1002 * since we need to ensure that we don't merge old info over newer
1003 * stuff in a stat cache entry. We're very conservative here: we don't
1004 * do the merge at all unless we ourselves create the stat cache
1005 * entry. That's pretty safe, and should work pretty well, since we
1006 * typically expect to do the stat cache creation ourselves.
1008 * We also have to take into account racing token revocations.
1010 for (i = 0; i < fidIndex; i++) {
1011 if ((&statsp[i])->errorCode)
1013 afid.Cell = adp->fid.Cell;
1014 afid.Fid.Volume = adp->fid.Fid.Volume;
1015 afid.Fid.Vnode = fidsp[i].Vnode;
1016 afid.Fid.Unique = fidsp[i].Unique;
1019 ObtainReadLock(&afs_xvcache);
1020 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1021 ReleaseReadLock(&afs_xvcache);
1022 } while (tvcp && retry);
1024 /* The entry may no longer exist */
1029 /* now we have the entry held, but we need to fill it in */
1030 ObtainWriteLock(&tvcp->lock, 131);
1032 /* if CBulkFetching is not set, or if the file size no longer
1033 * matches the value we placed there when we set the CBulkFetching
1034 * flag, then someone else has done something with this node,
1035 * and we may not have the latest status information for this
1036 * file. Leave the entry alone.
1038 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
1040 ReleaseWriteLock(&tvcp->lock);
1041 afs_PutVCache(tvcp);
1045 /* now copy ".." entry back out of volume structure, if necessary */
1046 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
1048 tvcp->mvid = (struct VenusFid *)
1049 osi_AllocSmallSpace(sizeof(struct VenusFid));
1050 *tvcp->mvid = dotdot;
1053 ObtainWriteLock(&afs_xvcache, 132);
1054 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1055 refpanic("Bulkstat VLRU inconsistent2");
1057 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1058 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1059 refpanic("Bulkstat VLRU inconsistent4");
1061 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1062 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1063 refpanic("Bulkstat VLRU inconsistent5");
1066 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
1067 QRemove(&tvcp->vlruq);
1068 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
1071 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1072 refpanic("Bulkstat VLRU inconsistent3");
1074 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1075 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1076 refpanic("Bulkstat VLRU inconsistent5");
1078 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1079 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1080 refpanic("Bulkstat VLRU inconsistent6");
1082 ReleaseWriteLock(&afs_xvcache);
1084 ObtainWriteLock(&afs_xcbhash, 494);
1086 /* We need to check the flags again. We may have missed
1087 * something while we were waiting for a lock.
1089 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
1091 ReleaseWriteLock(&tvcp->lock);
1092 ReleaseWriteLock(&afs_xcbhash);
1093 afs_PutVCache(tvcp);
1097 /* now merge in the resulting status back into the vnode.
1098 * We only do this if the entry looks clear.
1100 afs_ProcessFS(tvcp, &statsp[i], areqp);
1101 #if defined(AFS_LINUX22_ENV)
1102 afs_fill_inode(AFSTOV(tvcp), NULL); /* reset inode operations */
1105 /* do some accounting for bulk stats: mark this entry as
1106 * loaded, so we can tell if we use it before it gets
1109 tvcp->states |= CBulkStat;
1110 tvcp->states &= ~CBulkFetching;
1112 afs_bulkStatsDone++;
1114 /* merge in vol info */
1115 if (volStates & VRO)
1116 tvcp->states |= CRO;
1117 if (volStates & VBackup)
1118 tvcp->states |= CBackup;
1119 if (volStates & VForeign)
1120 tvcp->states |= CForeign;
1122 /* merge in the callback info */
1123 tvcp->states |= CTruth;
1125 /* get ptr to the callback we are interested in */
1128 if (tcbp->ExpirationTime != 0) {
1129 tvcp->cbExpires = tcbp->ExpirationTime + startTime;
1130 tvcp->callback = hostp;
1131 tvcp->states |= CStatd;
1132 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
1133 } else if (tvcp->states & CRO) {
1134 /* ordinary callback on a read-only volume -- AFS 3.2 style */
1135 tvcp->cbExpires = 3600 + startTime;
1136 tvcp->callback = hostp;
1137 tvcp->states |= CStatd;
1138 afs_QueueCallback(tvcp, CBHash(3600), volp);
1141 tvcp->states &= ~(CStatd | CUnique);
1142 afs_DequeueCallback(tvcp);
1143 if ((tvcp->states & CForeign) || (vType(tvcp) == VDIR))
1144 osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */
1146 ReleaseWriteLock(&afs_xcbhash);
1148 ReleaseWriteLock(&tvcp->lock);
1149 /* finally, we're done with the entry */
1150 afs_PutVCache(tvcp);
1151 } /* for all files we got back */
1153 /* finally return the pointer into the LRU queue */
1154 afs_PutVCache(lruvcp);
1157 /* Be sure to turn off the CBulkFetching flags */
1158 for (i = flagIndex; i < fidIndex; i++) {
1159 afid.Cell = adp->fid.Cell;
1160 afid.Fid.Volume = adp->fid.Fid.Volume;
1161 afid.Fid.Vnode = fidsp[i].Vnode;
1162 afid.Fid.Unique = fidsp[i].Unique;
1165 ObtainReadLock(&afs_xvcache);
1166 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1167 ReleaseReadLock(&afs_xvcache);
1168 } while (tvcp && retry);
1169 if (tvcp != NULL && (tvcp->states & CBulkFetching)
1170 && (tvcp->m.Length == statSeqNo)) {
1171 tvcp->states &= ~CBulkFetching;
1174 afs_PutVCache(tvcp);
1178 afs_PutVolume(volp, READ_LOCK);
1180 /* If we did the InlineBulk RPC pull out the return code */
1182 if ((&statsp[0])->errorCode) {
1183 afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->fid, areqp,
1184 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL);
1185 code = (&statsp[0])->errorCode;
1191 osi_FreeLargeSpace(statMemp);
1192 osi_FreeLargeSpace(cbfMemp);
1196 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
1197 #ifdef AFS_DARWIN80_ENV
1200 static int AFSDOBULK = 1;
1205 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int opflag, int wantparent)
1206 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
1207 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct pathname *pnp, int flags, struct vnode *rdir, struct AFS_UCRED *acred)
1208 #elif defined(UKERNEL)
1209 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int flags)
1211 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred)
1214 struct vrequest treq;
1216 register struct vcache *tvc = 0;
1217 register afs_int32 code;
1218 register afs_int32 bulkcode = 0;
1219 int pass = 0, hit = 0;
1220 int force_eval = afs_fakestat_enable ? 0 : 1;
1222 extern afs_int32 afs_mariner; /*Writing activity to log? */
1223 afs_hyper_t versionNo;
1224 int no_read_access = 0;
1225 struct sysname_info sysState; /* used only for @sys checking */
1226 int dynrootRetry = 1;
1227 struct afs_fakestat_state fakestate;
1228 int tryEvalOnly = 0;
1229 OSI_VC_CONVERT(adp);
1231 AFS_STATCNT(afs_lookup);
1232 afs_InitFakeStat(&fakestate);
1236 /*printf("Looking up %s\n", aname);*/
1238 if ((code = afs_InitReq(&treq, acred)))
1242 ndp->ni_dvp = AFSTOV(adp);
1243 #endif /* AFS_OSF_ENV */
1245 if (afs_fakestat_enable && adp->mvstat == 1) {
1246 if (strcmp(aname, ".directory") == 0)
1250 #if defined(AFS_DARWIN_ENV)
1251 /* Workaround for MacOSX Finder, which tries to look for
1252 * .DS_Store and Contents under every directory.
1254 if (afs_fakestat_enable && adp->mvstat == 1) {
1255 if (strcmp(aname, ".DS_Store") == 0)
1257 if (strcmp(aname, "Contents") == 0)
1263 code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
1265 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
1267 /*printf("Code is %d\n", code);*/
1269 if (tryEvalOnly && adp->mvstat == 1)
1274 *avcp = NULL; /* Since some callers don't initialize it */
1276 /* come back to here if we encounter a non-existent object in a read-only
1277 * volume's directory */
1280 *avcp = NULL; /* Since some callers don't initialize it */
1283 if (!(adp->states & CStatd) && !afs_InReadDir(adp)) {
1284 if ((code = afs_VerifyVCache2(adp, &treq))) {
1290 /* watch for ".." in a volume root */
1291 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1292 /* looking up ".." in root via special hacks */
1293 if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
1295 if (adp == afs_globalVp) {
1296 struct vnode *rvp = AFSTOV(adp);
1298 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
1299 ndp->ni_dvp = ndp->ni_vp;
1309 /* otherwise we have the fid here, so we use it */
1310 /*printf("Getting vcache\n");*/
1311 tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
1312 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
1313 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
1315 code = (tvc ? 0 : ENOENT);
1317 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1321 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code); */
1326 /* now check the access */
1327 if (treq.uid != adp->last_looker) {
1328 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1333 adp->last_looker = treq.uid;
1336 /* Check for read access as well. We need read access in order to
1337 * stat files, but not to stat subdirectories. */
1338 if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
1341 /* special case lookup of ".". Can we check for it sooner in this code,
1342 * for instance, way up before "redo:" ??
1343 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
1344 * invent a lightweight version of GetVCache.
1346 if (aname[0] == '.' && !aname[1]) { /* special case */
1347 ObtainReadLock(&afs_xvcache);
1349 ReleaseReadLock(&afs_xvcache);
1350 #ifdef AFS_DARWIN80_ENV
1351 vnode_get(AFSTOV(adp));
1356 if (adp && !VREFCOUNT_GT(adp, 0)) {
1363 * Special case lookup of ".." in the dynamic mount directory.
1364 * The parent of this directory is _always_ the AFS root volume.
1366 if (afs_IsDynrootMount(adp) &&
1367 aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1369 ObtainReadLock(&afs_xvcache);
1370 osi_vnhold(afs_globalVp, 0);
1371 ReleaseReadLock(&afs_xvcache);
1372 #ifdef AFS_DARWIN80_ENV
1373 vnode_get(AFSTOV(afs_globalVp));
1376 *avcp = tvc = afs_globalVp;
1382 * Special case lookups in the dynamic mount directory.
1383 * The names here take the form cell:volume, similar to a mount point.
1384 * EvalMountData parses that and returns a cell and volume ID, which
1385 * we use to construct the appropriate dynroot Fid.
1387 if (afs_IsDynrootMount(adp)) {
1388 struct VenusFid tfid;
1389 afs_uint32 cellidx, volid, vnoid;
1391 code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid);
1394 afs_GetDynrootMountFid(&tfid);
1395 tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
1396 tfid.Fid.Unique = volid;
1397 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1402 #ifdef AFS_LINUX26_ENV
1404 * Special case of the dynamic mount volume in a static root.
1405 * This is really unfortunate, but we need this for the translator.
1407 if (adp == afs_globalVp && !afs_GetDynrootEnable() &&
1408 !strcmp(aname, AFS_DYNROOT_MOUNTNAME)) {
1409 struct VenusFid tfid;
1411 afs_GetDynrootMountFid(&tfid);
1412 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1419 Check_AtSys(adp, aname, &sysState, &treq);
1420 tname = sysState.name;
1422 /* 1st Check_AtSys and lookup by tname is required here, for now,
1423 * because the dnlc is *not* told to remove entries for the parent
1424 * dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1425 * if the cached entry for the parent dir is invalidated for a
1427 * Otherwise, we'd be able to do a dnlc lookup on an entry ending
1428 * w/@sys and know the dnlc was consistent with reality. */
1429 tvc = osi_dnlc_lookup(adp, tname, WRITE_LOCK);
1430 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1432 if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1433 /* need read access on dir to stat non-directory / non-link */
1439 #ifdef AFS_LINUX22_ENV
1440 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1441 AFS_RELE(AFSTOV(tvc));
1448 #else /* non - LINUX */
1452 #endif /* linux22 */
1455 { /* sub-block just to reduce stack usage */
1456 register struct dcache *tdc;
1457 afs_size_t dirOffset, dirLen;
1458 struct VenusFid tfid;
1460 /* now we have to lookup the next fid */
1461 if (afs_InReadDir(adp))
1462 tdc = adp->dcreaddir;
1464 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq,
1465 &dirOffset, &dirLen, 1);
1467 *avcp = NULL; /* redundant, but harmless */
1472 /* now we will just call dir package with appropriate inode.
1473 * Dirs are always fetched in their entirety for now */
1474 ObtainReadLock(&adp->lock);
1475 ObtainReadLock(&tdc->lock);
1478 * Make sure that the data in the cache is current. There are two
1479 * cases we need to worry about:
1480 * 1. The cache data is being fetched by another process.
1481 * 2. The cache data is no longer valid
1483 * If a readdir is in progress _in this thread_, it has a shared
1484 * lock on the vcache and has obtained current data, so we just
1485 * use that. This eliminates several possible deadlocks.
1487 if (!afs_InReadDir(adp)) {
1488 while ((adp->states & CStatd)
1489 && (tdc->dflags & DFFetching)
1490 && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1491 ReleaseReadLock(&tdc->lock);
1492 ReleaseReadLock(&adp->lock);
1493 afs_osi_Sleep(&tdc->validPos);
1494 ObtainReadLock(&adp->lock);
1495 ObtainReadLock(&tdc->lock);
1497 if (!(adp->states & CStatd)
1498 || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1499 ReleaseReadLock(&tdc->lock);
1500 ReleaseReadLock(&adp->lock);
1502 if (tname && tname != aname)
1503 osi_FreeLargeSpace(tname);
1508 /* Save the version number for when we call osi_dnlc_enter */
1509 hset(versionNo, tdc->f.versionNo);
1512 * check for, and handle "@sys" if it's there. We should be able
1513 * to avoid the alloc and the strcpy with a little work, but it's
1514 * not pressing. If there aren't any remote users (ie, via the
1515 * NFS translator), we have a slightly easier job.
1516 * the faster way to do this is to check for *aname == '@' and if
1517 * it's there, check for @sys, otherwise, assume there's no @sys
1518 * then, if the lookup fails, check for .*@sys...
1520 /* above now implemented by Check_AtSys and Next_AtSys */
1522 /* lookup the name in the appropriate dir, and return a cache entry
1523 * on the resulting fid */
1525 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1528 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1529 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
1531 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1533 tname = sysState.name;
1535 ReleaseReadLock(&tdc->lock);
1536 if (!afs_InReadDir(adp))
1539 if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1540 ReleaseReadLock(&adp->lock);
1542 if (tname[0] == '.')
1543 afs_LookupAFSDB(tname + 1);
1545 afs_LookupAFSDB(tname);
1546 if (tname && tname != aname)
1547 osi_FreeLargeSpace(tname);
1550 ReleaseReadLock(&adp->lock);
1553 /* new fid has same cell and volume */
1554 tfid.Cell = adp->fid.Cell;
1555 tfid.Fid.Volume = adp->fid.Fid.Volume;
1556 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1557 ICL_TYPE_STRING, tname, ICL_TYPE_FID, &tfid,
1558 ICL_TYPE_INT32, code);
1561 if (code != ENOENT) {
1562 printf("LOOKUP dirLookupOff -> %d\n", code);
1567 /* prefetch some entries, if the dir is currently open. The variable
1568 * dirCookie tells us where to start prefetching from.
1570 if (!AFS_IS_DISCONNECTED &&
1571 AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)
1572 && !afs_IsDynroot(adp) && !afs_InReadDir(adp)) {
1574 /* if the entry is not in the cache, or is in the cache,
1575 * but hasn't been statd, then do a bulk stat operation.
1579 ObtainReadLock(&afs_xvcache);
1580 tvc = afs_FindVCache(&tfid, &retry, 0 /* !stats,!lru */ );
1581 ReleaseReadLock(&afs_xvcache);
1582 } while (tvc && retry);
1584 if (!tvc || !(tvc->states & CStatd))
1585 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1589 /* if the vcache isn't usable, release it */
1590 if (tvc && !(tvc->states & CStatd)) {
1599 /* now get the status info, if we don't already have it */
1600 /* This is kind of weird, but we might wind up accidentally calling
1601 * RXAFS_Lookup because we happened upon a file which legitimately
1602 * has a 0 uniquifier. That is the result of allowing unique to wrap
1603 * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1604 * the file has not yet been looked up.
1607 afs_int32 cached = 0;
1608 if (!tfid.Fid.Unique && (adp->states & CForeign)) {
1609 tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
1611 if (!tvc && !bulkcode) { /* lookup failed or wasn't called */
1612 tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
1615 } /* sub-block just to reduce stack usage */
1618 if (adp->states & CForeign)
1619 tvc->states |= CForeign;
1620 tvc->parentVnode = adp->fid.Fid.Vnode;
1621 tvc->parentUnique = adp->fid.Fid.Unique;
1622 tvc->states &= ~CBulkStat;
1624 if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
1625 ObtainSharedLock(&tvc->lock, 680);
1626 if (!tvc->linkData) {
1627 UpgradeSToWLock(&tvc->lock, 681);
1628 code = afs_HandleLink(tvc, &treq);
1629 ConvertWToRLock(&tvc->lock);
1631 ConvertSToRLock(&tvc->lock);
1634 if (!code && !afs_strchr(tvc->linkData, ':'))
1636 ReleaseReadLock(&tvc->lock);
1638 if (tvc->mvstat == 1 && (tvc->states & CMValid) && tvc->mvid != NULL)
1639 force_eval = 1; /* This is now almost for free, get it correct */
1641 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1642 if (!(flags & AFS_LOOKUP_NOEVAL))
1643 /* don't eval mount points */
1644 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1645 if (tvc->mvstat == 1 && force_eval) {
1646 /* a mt point, possibly unevaluated */
1647 struct volume *tvolp;
1649 ObtainWriteLock(&tvc->lock, 133);
1650 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1651 ReleaseWriteLock(&tvc->lock);
1656 afs_PutVolume(tvolp, WRITE_LOCK);
1660 /* next, we want to continue using the target of the mt point */
1661 if (tvc->mvid && (tvc->states & CMValid)) {
1663 /* now lookup target, to set .. pointer */
1664 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1665 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID,
1667 uvc = tvc; /* remember for later */
1669 if (tvolp && (tvolp->states & VForeign)) {
1670 /* XXXX tvolp has ref cnt on but not locked! XXX */
1672 afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
1674 tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
1676 afs_PutVCache(uvc); /* we're done with it */
1681 afs_PutVolume(tvolp, WRITE_LOCK);
1686 /* now, if we came via a new mt pt (say because of a new
1687 * release of a R/O volume), we must reevaluate the ..
1688 * ptr to point back to the appropriate place */
1690 ObtainWriteLock(&tvc->lock, 134);
1691 if (tvc->mvid == NULL) {
1692 tvc->mvid = (struct VenusFid *)
1693 osi_AllocSmallSpace(sizeof(struct VenusFid));
1695 /* setup backpointer */
1696 *tvc->mvid = tvolp->dotdot;
1697 ReleaseWriteLock(&tvc->lock);
1698 afs_PutVolume(tvolp, WRITE_LOCK);
1704 afs_PutVolume(tvolp, WRITE_LOCK);
1709 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1714 /* if we get here, we found something in a directory that couldn't
1715 * be located (a Multics "connection failure"). If the volume is
1716 * read-only, we try flushing this entry from the cache and trying
1718 if (!AFS_IS_DISCONNECTED) {
1721 tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
1723 if (tv->states & VRO) {
1724 pass = 1; /* try this *once* */
1725 ObtainWriteLock(&afs_xcbhash, 495);
1726 afs_DequeueCallback(adp);
1727 /* re-stat to get later version */
1728 adp->states &= ~CStatd;
1729 ReleaseWriteLock(&afs_xcbhash);
1730 osi_dnlc_purgedp(adp);
1731 afs_PutVolume(tv, READ_LOCK);
1734 afs_PutVolume(tv, READ_LOCK);
1739 /*printf("Network down in afs_lookup\n");*/
1745 /* put the network buffer back, if need be */
1746 if (tname != aname && tname)
1747 osi_FreeLargeSpace(tname);
1750 /* Handle RENAME; only need to check rename "." */
1751 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1752 if (!FidCmp(&(tvc->fid), &(adp->fid))) {
1753 afs_PutVCache(*avcp);
1755 afs_PutFakeStat(&fakestate);
1756 return afs_CheckCode(EISDIR, &treq, 18);
1759 #endif /* AFS_OSF_ENV */
1762 afs_AddMarinerName(aname, tvc);
1764 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1765 if (!(flags & AFS_LOOKUP_NOEVAL))
1766 /* Here we don't enter the name into the DNLC because we want the
1767 * evaluated mount dir to be there (the vcache for the mounted volume)
1768 * rather than the vc of the mount point itself. we can still find the
1769 * mount point's vc in the vcache by its fid. */
1770 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1771 if (!hit && force_eval) {
1772 osi_dnlc_enter(adp, aname, tvc, &versionNo);
1774 #ifdef AFS_LINUX20_ENV
1775 /* So Linux inode cache is up to date. */
1776 code = afs_VerifyVCache(tvc, &treq);
1778 afs_PutFakeStat(&fakestate);
1779 AFS_DISCON_UNLOCK();
1780 return 0; /* can't have been any errors if hit and !code */
1787 code = afs_CheckCode(code, &treq, 19);
1789 /* If there is an error, make sure *avcp is null.
1790 * Alphas panic otherwise - defect 10719.
1795 afs_PutFakeStat(&fakestate);
1796 AFS_DISCON_UNLOCK();