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->f.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->f.states, avc->f.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->f.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->f.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->f.fid; /* setup back pointer to mtpoint */
317 (*avolpp)->dotdot = advc->f.fid;
325 * Must be called on an afs_fakestat_state object before calling
326 * afs_EvalFakeStat or afs_PutFakeStat. Calling afs_PutFakeStat
327 * without calling afs_EvalFakeStat is legal, as long as this
328 * function is called.
331 afs_InitFakeStat(struct afs_fakestat_state *state)
333 if (!afs_fakestat_enable)
338 state->need_release = 0;
342 * afs_EvalFakeStat_int
344 * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
345 * which is called by those wrapper functions.
347 * Only issues RPCs if canblock is non-zero.
350 afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
351 struct vrequest *areq, int canblock)
353 struct vcache *tvc, *root_vp;
354 struct volume *tvolp = NULL;
357 if (!afs_fakestat_enable)
360 osi_Assert(state->valid == 1);
361 osi_Assert(state->did_eval == 0);
365 if (tvc->mvstat != 1)
368 /* Is the call to VerifyVCache really necessary? */
369 code = afs_VerifyVCache(tvc, areq);
373 ObtainWriteLock(&tvc->lock, 599);
374 code = EvalMountPoint(tvc, NULL, &tvolp, areq);
375 ReleaseWriteLock(&tvc->lock);
379 tvolp->dotdot = tvc->f.fid;
380 tvolp->dotdot.Fid.Vnode = tvc->f.parent.vnode;
381 tvolp->dotdot.Fid.Unique = tvc->f.parent.unique;
384 if (tvc->mvid && (tvc->f.states & CMValid)) {
390 ObtainWriteLock(&afs_xvcache, 597);
391 root_vp = afs_FindVCache(tvc->mvid, &retry, IS_WLOCK);
392 if (root_vp && retry) {
393 ReleaseWriteLock(&afs_xvcache);
394 afs_PutVCache(root_vp);
396 } while (root_vp && retry);
397 ReleaseWriteLock(&afs_xvcache);
399 root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
402 code = canblock ? ENOENT : 0;
405 #ifdef AFS_DARWIN80_ENV
406 root_vp->f.m.Type = VDIR;
408 code = afs_darwin_finalizevnode(root_vp, NULL, NULL, 0);
411 vnode_ref(AFSTOV(root_vp));
413 if (tvolp && !afs_InReadDir(root_vp)) {
414 /* Is this always kosher? Perhaps we should instead use
415 * NBObtainWriteLock to avoid potential deadlock.
417 ObtainWriteLock(&root_vp->lock, 598);
419 root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
420 *root_vp->mvid = tvolp->dotdot;
421 ReleaseWriteLock(&root_vp->lock);
423 state->need_release = 1;
424 state->root_vp = root_vp;
428 code = canblock ? ENOENT : 0;
433 afs_PutVolume(tvolp, WRITE_LOCK);
440 * Automatically does the equivalent of EvalMountPoint for vcache entries
441 * which are mount points. Remembers enough state to properly release
442 * the volume root vcache when afs_PutFakeStat() is called.
444 * State variable must be initialized by afs_InitFakeState() beforehand.
446 * Returns 0 when everything succeeds and *avcp points to the vcache entry
447 * that should be used for the real vnode operation. Returns non-zero if
448 * something goes wrong and the error code should be returned to the user.
451 afs_EvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
452 struct vrequest *areq)
454 return afs_EvalFakeStat_int(avcp, state, areq, 1);
458 * afs_TryEvalFakeStat
460 * Same as afs_EvalFakeStat, but tries not to talk to remote servers
461 * and only evaluate the mount point if all the data is already in
464 * Returns 0 if everything succeeds and *avcp points to a valid
465 * vcache entry (possibly evaluated).
468 afs_TryEvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
469 struct vrequest *areq)
471 return afs_EvalFakeStat_int(avcp, state, areq, 0);
477 * Perform any necessary cleanup at the end of a vnode op, given that
478 * afs_InitFakeStat was previously called with this state.
481 afs_PutFakeStat(struct afs_fakestat_state *state)
483 if (!afs_fakestat_enable)
486 osi_Assert(state->valid == 1);
487 if (state->need_release)
488 afs_PutVCache(state->root_vp);
493 afs_ENameOK(register char *aname)
497 AFS_STATCNT(ENameOK);
498 tlen = strlen(aname);
499 if (tlen >= 4 && strcmp(aname + tlen - 4, "@sys") == 0)
505 afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
506 register char *bufp, int *num, char **sysnamelist[])
508 register struct unixuser *au;
509 register afs_int32 error;
511 AFS_STATCNT(getsysname);
513 *sysnamelist = afs_sysnamelist;
515 if (!afs_nfsexporter)
516 strcpy(bufp, (*sysnamelist)[0]);
518 au = afs_GetUser(areq->uid, adp->f.fid.Cell, 0);
520 error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
522 strcpy(bufp, "@sys");
526 strcpy(bufp, (*sysnamelist)[0]);
529 strcpy(bufp, afs_sysname);
536 Check_AtSys(register struct vcache *avc, const char *aname,
537 struct sysname_info *state, struct vrequest *areq)
540 char **sysnamelist[MAXNUMSYSNAMES];
542 if (AFS_EQ_ATSYS(aname)) {
544 state->name = (char *)osi_AllocLargeSpace(MAXSYSNAME);
547 afs_getsysname(areq, avc, state->name, &num, sysnamelist);
552 state->name = (char *)aname;
557 Next_AtSys(register struct vcache *avc, struct vrequest *areq,
558 struct sysname_info *state)
560 int num = afs_sysnamecount;
561 char **sysnamelist[MAXNUMSYSNAMES];
563 if (state->index == -1)
564 return 0; /* No list */
566 /* Check for the initial state of aname != "@sys" in Check_AtSys */
567 if (state->offset == -1 && state->allocked == 0) {
568 register char *tname;
570 /* Check for .*@sys */
571 for (tname = state->name; *tname; tname++)
572 /*Move to the end of the string */ ;
574 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
575 state->offset = (tname - 4) - state->name;
576 tname = (char *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
577 strncpy(tname, state->name, state->offset);
582 afs_getsysname(areq, avc, state->name + state->offset, &num,
586 return 0; /* .*@sys doesn't match either */
588 register struct unixuser *au;
589 register afs_int32 error;
591 *sysnamelist = afs_sysnamelist;
593 if (afs_nfsexporter) {
594 au = afs_GetUser(areq->uid, avc->f.fid.Cell, 0);
597 EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
605 if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
606 return 0; /* end of list */
608 strcpy(state->name + state->offset, (*sysnamelist)[(unsigned int)state->index]);
612 extern int BlobScan(struct dcache * afile, afs_int32 ablob);
614 /* called with an unlocked directory and directory cookie. Areqp
615 * describes who is making the call.
616 * Scans the next N (about 30, typically) directory entries, and does
617 * a bulk stat call to stat them all.
619 * Must be very careful when merging in RPC responses, since we dont
620 * want to overwrite newer info that was added by a file system mutating
621 * call that ran concurrently with our bulk stat call.
623 * We do that, as described below, by not merging in our info (always
624 * safe to skip the merge) if the status info is valid in the vcache entry.
626 * If adapt ever implements the bulk stat RPC, then this code will need to
627 * ensure that vcaches created for failed RPC's to older servers have the
630 static struct vcache *BStvc = NULL;
633 afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
635 int nentries; /* # of entries to prefetch */
636 int nskip; /* # of slots in the LRU queue to skip */
637 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
638 struct dcache *dcp; /* chunk containing the dir block */
639 char *statMemp; /* status memory block */
640 char *cbfMemp; /* callback and fid memory block */
641 afs_size_t temp; /* temp for holding chunk length, &c. */
642 struct AFSFid *fidsp; /* file IDs were collecting */
643 struct AFSCallBack *cbsp; /* call back pointers */
644 struct AFSCallBack *tcbp; /* temp callback ptr */
645 struct AFSFetchStatus *statsp; /* file status info */
646 struct AFSVolSync volSync; /* vol sync return info */
647 struct vcache *tvcp; /* temp vcp */
648 struct afs_q *tq; /* temp queue variable */
649 AFSCBFids fidParm; /* file ID parm for bulk stat */
650 AFSBulkStats statParm; /* stat info parm for bulk stat */
651 int fidIndex = 0; /* which file were stating */
652 struct afs_conn *tcp = 0; /* conn for call */
653 AFSCBs cbParm; /* callback parm for bulk stat */
654 struct server *hostp = 0; /* host we got callback from */
655 long startTime; /* time we started the call,
656 * for callback expiration base
658 afs_size_t statSeqNo = 0; /* Valued of file size to detect races */
659 int code; /* error code */
660 long newIndex; /* new index in the dir */
661 struct DirEntry *dirEntryp; /* dir entry we are examining */
663 struct VenusFid afid; /* file ID we are using now */
664 struct VenusFid tfid; /* another temp. file ID */
665 afs_int32 retry; /* handle low-level SGI MP race conditions */
666 long volStates; /* flags from vol structure */
667 struct volume *volp = 0; /* volume ptr */
668 struct VenusFid dotdot = {0, 0, 0};
669 int flagIndex = 0; /* First file with bulk fetch flag set */
670 int inlinebulk = 0; /* Did we use InlineBulk RPC or not? */
672 #ifdef AFS_DARWIN80_ENV
673 panic("bulkstatus doesn't work on AFS_DARWIN80_ENV. don't call it");
675 /* first compute some basic parameters. We dont want to prefetch more
676 * than a fraction of the cache in any given call, and we want to preserve
677 * a portion of the LRU queue in any event, so as to avoid thrashing
678 * the entire stat cache (we will at least leave some of it alone).
679 * presently dont stat more than 1/8 the cache in any one call. */
680 nentries = afs_cacheStats / 8;
682 /* dont bother prefetching more than one calls worth of info */
683 if (nentries > AFSCBMAX)
686 /* heuristic to make sure that things fit in 4K. This means that
687 * we shouldnt make it any bigger than 47 entries. I am typically
688 * going to keep it a little lower, since we don't want to load
689 * too much of the stat cache.
694 /* now, to reduce the stack size, well allocate two 4K blocks,
695 * one for fids and callbacks, and one for stat info. Well set
696 * up our pointers to the memory from there, too.
698 statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
699 statsp = (struct AFSFetchStatus *)statMemp;
701 osi_AllocLargeSpace(nentries *
702 (sizeof(AFSCallBack) + sizeof(AFSFid)));
703 fidsp = (AFSFid *) cbfMemp;
704 cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
706 /* next, we must iterate over the directory, starting from the specified
707 * cookie offset (dirCookie), and counting out nentries file entries.
708 * We skip files that already have stat cache entries, since we
709 * dont want to bulk stat files that are already in the cache.
712 code = afs_VerifyVCache(adp, areqp);
716 dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
722 /* lock the directory cache entry */
723 ObtainReadLock(&adp->lock);
724 ObtainReadLock(&dcp->lock);
727 * Make sure that the data in the cache is current. There are two
728 * cases we need to worry about:
729 * 1. The cache data is being fetched by another process.
730 * 2. The cache data is no longer valid
732 while ((adp->f.states & CStatd)
733 && (dcp->dflags & DFFetching)
734 && hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
735 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
736 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, dcp,
737 ICL_TYPE_INT32, dcp->dflags);
738 ReleaseReadLock(&dcp->lock);
739 ReleaseReadLock(&adp->lock);
740 afs_osi_Sleep(&dcp->validPos);
741 ObtainReadLock(&adp->lock);
742 ObtainReadLock(&dcp->lock);
744 if (!(adp->f.states & CStatd)
745 || !hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
746 ReleaseReadLock(&dcp->lock);
747 ReleaseReadLock(&adp->lock);
752 /* Generate a sequence number so we can tell whether we should
753 * store the attributes when processing the response. This number is
754 * stored in the file size when we set the CBulkFetching bit. If the
755 * CBulkFetching is still set and this value hasn't changed, then
756 * we know we were the last to set CBulkFetching bit for this file,
757 * and it is safe to set the status information for this file.
759 statSeqNo = bulkStatCounter++;
761 /* now we have dir data in the cache, so scan the dir page */
764 while (1) { /* Should probably have some constant bound */
765 /* look for first safe entry to examine in the directory. BlobScan
766 * looks for a the 1st allocated dir after the dirCookie slot.
768 newIndex = BlobScan(dcp, (dirCookie >> 5));
772 /* remember the updated directory cookie */
773 dirCookie = newIndex << 5;
775 /* get a ptr to the dir entry */
777 (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
781 /* dont copy more than we have room for */
782 if (fidIndex >= nentries) {
783 DRelease((struct buffer *)dirEntryp, 0);
787 /* now, if the dir entry looks good, copy it out to our list. Vnode
788 * 0 means deleted, although it should also be free were it deleted.
790 if (dirEntryp->fid.vnode != 0) {
791 /* dont copy entries we have in our cache. This check will
792 * also make us skip "." and probably "..", unless it has
793 * disappeared from the cache since we did our namei call.
795 tfid.Cell = adp->f.fid.Cell;
796 tfid.Fid.Volume = adp->f.fid.Fid.Volume;
797 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
798 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
801 ObtainWriteLock(&afs_xvcache, 130);
802 tvcp = afs_FindVCache(&tfid, &retry, IS_WLOCK /* no stats | LRU */ );
804 ReleaseWriteLock(&afs_xvcache);
807 } while (tvcp && retry);
808 if (!tvcp) { /* otherwise, create manually */
809 tvcp = afs_NewVCache(&tfid, hostp);
812 ObtainWriteLock(&tvcp->lock, 505);
813 ReleaseWriteLock(&afs_xvcache);
814 afs_RemoveVCB(&tfid);
815 ReleaseWriteLock(&tvcp->lock);
817 ReleaseWriteLock(&afs_xvcache);
820 ReleaseWriteLock(&afs_xvcache);
824 DRelease((struct buffer *)dirEntryp, 0);
825 ReleaseReadLock(&dcp->lock);
826 ReleaseReadLock(&adp->lock);
828 goto done; /* can happen if afs_NewVCache fails */
831 #ifdef AFS_DARWIN80_ENV
832 if (tvcp->f.states & CVInit) {
833 /* XXX don't have status yet, so creating the vnode is
834 not yet useful. we would get CDeadVnode set, and the
835 upcoming PutVCache will cause the vcache to be flushed &
836 freed, which in turn means the bulkstatus results won't
840 /* WARNING: afs_DoBulkStat uses the Length field to store a
841 * sequence number for each bulk status request. Under no
842 * circumstances should afs_DoBulkStat store a sequence number
843 * if the new length will be ignored when afs_ProcessFS is
844 * called with new stats. */
846 if (!(tvcp->f.states & (CStatd | CBulkFetching))
847 && (tvcp->execsOrWriters <= 0)
848 && !afs_DirtyPages(tvcp)
849 && !AFS_VN_MAPPED((vnode_t *) tvcp))
851 if (!(tvcp->f.states & (CStatd | CBulkFetching))
852 && (tvcp->execsOrWriters <= 0)
853 && !afs_DirtyPages(tvcp))
857 /* this entry doesnt exist in the cache, and is not
858 * already being fetched by someone else, so add it to the
859 * list of file IDs to obtain.
861 * We detect a callback breaking race condition by checking the
862 * CBulkFetching state bit and the value in the file size.
863 * It is safe to set the status only if the CBulkFetching
864 * flag is still set and the value in the file size does
867 * Don't fetch status for dirty files. We need to
868 * preserve the value of the file size. We could
869 * flush the pages, but it wouldn't be worthwhile.
871 memcpy((char *)(fidsp + fidIndex), (char *)&tfid.Fid,
873 tvcp->f.states |= CBulkFetching;
874 tvcp->f.m.Length = statSeqNo;
880 /* if dir vnode has non-zero entry */
881 /* move to the next dir entry by adding in the # of entries
882 * used by this dir entry.
884 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
885 DRelease((struct buffer *)dirEntryp, 0);
889 } /* while loop over all dir entries */
891 /* now release the dir lock and prepare to make the bulk RPC */
892 ReleaseReadLock(&dcp->lock);
893 ReleaseReadLock(&adp->lock);
895 /* release the chunk */
898 /* dont make a null call */
903 /* setup the RPC parm structures */
904 fidParm.AFSCBFids_len = fidIndex;
905 fidParm.AFSCBFids_val = fidsp;
906 statParm.AFSBulkStats_len = fidIndex;
907 statParm.AFSBulkStats_val = statsp;
908 cbParm.AFSCBs_len = fidIndex;
909 cbParm.AFSCBs_val = cbsp;
911 /* start the timer; callback expirations are relative to this */
912 startTime = osi_Time();
914 tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK);
916 hostp = tcp->srvr->server;
917 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
920 if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
922 RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
924 if (code == RXGEN_OPCODE) {
925 tcp->srvr->server->flags |= SNO_INLINEBULK;
928 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
935 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
943 (tcp, code, &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
946 /* now, if we didnt get the info, bail out. */
950 /* we need vol flags to create the entries properly */
951 dotdot.Fid.Volume = 0;
952 volp = afs_GetVolume(&adp->f.fid, areqp, READ_LOCK);
954 volStates = volp->states;
955 if (volp->dotdot.Fid.Volume != 0)
956 dotdot = volp->dotdot;
960 /* find the place to merge the info into We do this by skipping
961 * nskip entries in the LRU queue. The more we skip, the more
962 * we preserve, since the head of the VLRU queue is the most recently
966 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
967 ObtainReadLock(&afs_xvcache);
969 /* actually a serious error, probably should panic. Probably will
970 * panic soon, oh well. */
971 ReleaseReadLock(&afs_xvcache);
972 afs_warnuser("afs_DoBulkStat: VLRU empty!");
975 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
976 refpanic("Bulkstat VLRU inconsistent");
978 for (tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
981 else if (QNext(QPrev(tq)) != tq) {
983 refpanic("BulkStat VLRU inconsistent");
989 lruvcp = QTOV(VLRU.next);
991 /* now we have to hold this entry, so that it does not get moved
992 * into the free list while we're running. It could still get
993 * moved within the lru queue, but hopefully that will be rare; it
994 * doesn't hurt nearly as much.
997 osi_vnhold(lruvcp, &retry);
998 ReleaseReadLock(&afs_xvcache); /* could be read lock */
1002 /* otherwise, merge in the info. We have to be quite careful here,
1003 * since we need to ensure that we don't merge old info over newer
1004 * stuff in a stat cache entry. We're very conservative here: we don't
1005 * do the merge at all unless we ourselves create the stat cache
1006 * entry. That's pretty safe, and should work pretty well, since we
1007 * typically expect to do the stat cache creation ourselves.
1009 * We also have to take into account racing token revocations.
1011 for (i = 0; i < fidIndex; i++) {
1012 if ((&statsp[i])->errorCode)
1014 afid.Cell = adp->f.fid.Cell;
1015 afid.Fid.Volume = adp->f.fid.Fid.Volume;
1016 afid.Fid.Vnode = fidsp[i].Vnode;
1017 afid.Fid.Unique = fidsp[i].Unique;
1020 ObtainReadLock(&afs_xvcache);
1021 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1022 ReleaseReadLock(&afs_xvcache);
1023 } while (tvcp && retry);
1025 /* The entry may no longer exist */
1030 /* now we have the entry held, but we need to fill it in */
1031 ObtainWriteLock(&tvcp->lock, 131);
1033 /* if CBulkFetching is not set, or if the file size no longer
1034 * matches the value we placed there when we set the CBulkFetching
1035 * flag, then someone else has done something with this node,
1036 * and we may not have the latest status information for this
1037 * file. Leave the entry alone.
1039 if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
1041 ReleaseWriteLock(&tvcp->lock);
1042 afs_PutVCache(tvcp);
1046 /* now copy ".." entry back out of volume structure, if necessary */
1047 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
1049 tvcp->mvid = (struct VenusFid *)
1050 osi_AllocSmallSpace(sizeof(struct VenusFid));
1051 *tvcp->mvid = dotdot;
1054 ObtainWriteLock(&afs_xvcache, 132);
1055 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1056 refpanic("Bulkstat VLRU inconsistent2");
1058 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1059 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1060 refpanic("Bulkstat VLRU inconsistent4");
1062 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1063 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1064 refpanic("Bulkstat VLRU inconsistent5");
1067 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
1068 QRemove(&tvcp->vlruq);
1069 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
1072 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1073 refpanic("Bulkstat VLRU inconsistent3");
1075 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1076 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1077 refpanic("Bulkstat VLRU inconsistent5");
1079 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1080 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1081 refpanic("Bulkstat VLRU inconsistent6");
1083 ReleaseWriteLock(&afs_xvcache);
1085 ObtainWriteLock(&afs_xcbhash, 494);
1087 /* We need to check the flags again. We may have missed
1088 * something while we were waiting for a lock.
1090 if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
1092 ReleaseWriteLock(&tvcp->lock);
1093 ReleaseWriteLock(&afs_xcbhash);
1094 afs_PutVCache(tvcp);
1098 /* now merge in the resulting status back into the vnode.
1099 * We only do this if the entry looks clear.
1101 afs_ProcessFS(tvcp, &statsp[i], areqp);
1102 #if defined(AFS_LINUX22_ENV)
1103 afs_fill_inode(AFSTOV(tvcp), NULL); /* reset inode operations */
1106 /* do some accounting for bulk stats: mark this entry as
1107 * loaded, so we can tell if we use it before it gets
1110 tvcp->f.states |= CBulkStat;
1111 tvcp->f.states &= ~CBulkFetching;
1113 afs_bulkStatsDone++;
1115 /* merge in vol info */
1116 if (volStates & VRO)
1117 tvcp->f.states |= CRO;
1118 if (volStates & VBackup)
1119 tvcp->f.states |= CBackup;
1120 if (volStates & VForeign)
1121 tvcp->f.states |= CForeign;
1123 /* merge in the callback info */
1124 tvcp->f.states |= CTruth;
1126 /* get ptr to the callback we are interested in */
1129 if (tcbp->ExpirationTime != 0) {
1130 tvcp->cbExpires = tcbp->ExpirationTime + startTime;
1131 tvcp->callback = hostp;
1132 tvcp->f.states |= CStatd;
1133 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
1134 } else if (tvcp->f.states & CRO) {
1135 /* ordinary callback on a read-only volume -- AFS 3.2 style */
1136 tvcp->cbExpires = 3600 + startTime;
1137 tvcp->callback = hostp;
1138 tvcp->f.states |= CStatd;
1139 afs_QueueCallback(tvcp, CBHash(3600), volp);
1142 tvcp->f.states &= ~(CStatd | CUnique);
1143 afs_DequeueCallback(tvcp);
1144 if ((tvcp->f.states & CForeign) || (vType(tvcp) == VDIR))
1145 osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */
1147 ReleaseWriteLock(&afs_xcbhash);
1149 ReleaseWriteLock(&tvcp->lock);
1150 /* finally, we're done with the entry */
1151 afs_PutVCache(tvcp);
1152 } /* for all files we got back */
1154 /* finally return the pointer into the LRU queue */
1155 afs_PutVCache(lruvcp);
1158 /* Be sure to turn off the CBulkFetching flags */
1159 for (i = flagIndex; i < fidIndex; i++) {
1160 afid.Cell = adp->f.fid.Cell;
1161 afid.Fid.Volume = adp->f.fid.Fid.Volume;
1162 afid.Fid.Vnode = fidsp[i].Vnode;
1163 afid.Fid.Unique = fidsp[i].Unique;
1166 ObtainReadLock(&afs_xvcache);
1167 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1168 ReleaseReadLock(&afs_xvcache);
1169 } while (tvcp && retry);
1170 if (tvcp != NULL && (tvcp->f.states & CBulkFetching)
1171 && (tvcp->f.m.Length == statSeqNo)) {
1172 tvcp->f.states &= ~CBulkFetching;
1175 afs_PutVCache(tvcp);
1179 afs_PutVolume(volp, READ_LOCK);
1181 /* If we did the InlineBulk RPC pull out the return code */
1183 if ((&statsp[0])->errorCode) {
1184 afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->f.fid, areqp,
1185 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL);
1186 code = (&statsp[0])->errorCode;
1192 osi_FreeLargeSpace(statMemp);
1193 osi_FreeLargeSpace(cbfMemp);
1197 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
1198 #ifdef AFS_DARWIN80_ENV
1201 static int AFSDOBULK = 1;
1206 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int opflag, int wantparent)
1207 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
1208 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct pathname *pnp, int flags, struct vnode *rdir, struct AFS_UCRED *acred)
1209 #elif defined(UKERNEL)
1210 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred, int flags)
1212 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct AFS_UCRED *acred)
1215 struct vrequest treq;
1217 register struct vcache *tvc = 0;
1218 register afs_int32 code;
1219 register afs_int32 bulkcode = 0;
1220 int pass = 0, hit = 0;
1221 int force_eval = afs_fakestat_enable ? 0 : 1;
1223 extern afs_int32 afs_mariner; /*Writing activity to log? */
1224 afs_hyper_t versionNo;
1225 int no_read_access = 0;
1226 struct sysname_info sysState; /* used only for @sys checking */
1227 int dynrootRetry = 1;
1228 struct afs_fakestat_state fakestate;
1229 int tryEvalOnly = 0;
1230 OSI_VC_CONVERT(adp);
1232 AFS_STATCNT(afs_lookup);
1233 afs_InitFakeStat(&fakestate);
1237 if ((code = afs_InitReq(&treq, acred)))
1241 ndp->ni_dvp = AFSTOV(adp);
1242 #endif /* AFS_OSF_ENV */
1244 if (afs_fakestat_enable && adp->mvstat == 1) {
1245 if (strcmp(aname, ".directory") == 0)
1249 #if defined(AFS_DARWIN_ENV)
1250 /* Workaround for MacOSX Finder, which tries to look for
1251 * .DS_Store and Contents under every directory.
1253 if (afs_fakestat_enable && adp->mvstat == 1) {
1254 if (strcmp(aname, ".DS_Store") == 0)
1256 if (strcmp(aname, "Contents") == 0)
1262 code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
1264 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
1266 /*printf("Code is %d\n", code);*/
1268 if (tryEvalOnly && adp->mvstat == 1)
1273 *avcp = NULL; /* Since some callers don't initialize it */
1275 /* come back to here if we encounter a non-existent object in a read-only
1276 * volume's directory */
1279 *avcp = NULL; /* Since some callers don't initialize it */
1282 if (!(adp->f.states & CStatd) && !afs_InReadDir(adp)) {
1283 if ((code = afs_VerifyVCache2(adp, &treq))) {
1289 /* watch for ".." in a volume root */
1290 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1291 /* looking up ".." in root via special hacks */
1292 if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
1294 if (adp == afs_globalVp) {
1295 struct vnode *rvp = AFSTOV(adp);
1297 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
1298 ndp->ni_dvp = ndp->ni_vp;
1308 /* otherwise we have the fid here, so we use it */
1309 /*printf("Getting vcache\n");*/
1310 tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
1311 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
1312 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
1314 code = (tvc ? 0 : ENOENT);
1316 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1320 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code); */
1325 /* now check the access */
1326 if (treq.uid != adp->last_looker) {
1327 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1332 adp->last_looker = treq.uid;
1335 /* Check for read access as well. We need read access in order to
1336 * stat files, but not to stat subdirectories. */
1337 if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
1340 /* special case lookup of ".". Can we check for it sooner in this code,
1341 * for instance, way up before "redo:" ??
1342 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
1343 * invent a lightweight version of GetVCache.
1345 if (aname[0] == '.' && !aname[1]) { /* special case */
1346 ObtainReadLock(&afs_xvcache);
1348 ReleaseReadLock(&afs_xvcache);
1349 #ifdef AFS_DARWIN80_ENV
1350 vnode_get(AFSTOV(adp));
1355 if (adp && !VREFCOUNT_GT(adp, 0)) {
1362 * Special case lookup of ".." in the dynamic mount directory.
1363 * The parent of this directory is _always_ the AFS root volume.
1365 if (afs_IsDynrootMount(adp) &&
1366 aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1368 ObtainReadLock(&afs_xvcache);
1369 osi_vnhold(afs_globalVp, 0);
1370 ReleaseReadLock(&afs_xvcache);
1371 #ifdef AFS_DARWIN80_ENV
1372 vnode_get(AFSTOV(afs_globalVp));
1375 *avcp = tvc = afs_globalVp;
1381 * Special case lookups in the dynamic mount directory.
1382 * The names here take the form cell:volume, similar to a mount point.
1383 * EvalMountData parses that and returns a cell and volume ID, which
1384 * we use to construct the appropriate dynroot Fid.
1386 if (afs_IsDynrootMount(adp)) {
1387 struct VenusFid tfid;
1388 afs_uint32 cellidx, volid, vnoid;
1390 code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid);
1393 afs_GetDynrootMountFid(&tfid);
1394 tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
1395 tfid.Fid.Unique = volid;
1396 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1401 #ifdef AFS_LINUX26_ENV
1403 * Special case of the dynamic mount volume in a static root.
1404 * This is really unfortunate, but we need this for the translator.
1406 if (adp == afs_globalVp && !afs_GetDynrootEnable() &&
1407 !strcmp(aname, AFS_DYNROOT_MOUNTNAME)) {
1408 struct VenusFid tfid;
1410 afs_GetDynrootMountFid(&tfid);
1411 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1418 Check_AtSys(adp, aname, &sysState, &treq);
1419 tname = sysState.name;
1421 /* 1st Check_AtSys and lookup by tname is required here, for now,
1422 * because the dnlc is *not* told to remove entries for the parent
1423 * dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1424 * if the cached entry for the parent dir is invalidated for a
1426 * Otherwise, we'd be able to do a dnlc lookup on an entry ending
1427 * w/@sys and know the dnlc was consistent with reality. */
1428 tvc = osi_dnlc_lookup(adp, tname, WRITE_LOCK);
1429 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1431 if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1432 /* need read access on dir to stat non-directory / non-link */
1433 #ifndef AFS_FBSD80_ENV
1440 #ifdef AFS_LINUX22_ENV
1441 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1442 AFS_RELE(AFSTOV(tvc));
1449 #else /* non - LINUX */
1453 #endif /* linux22 */
1456 { /* sub-block just to reduce stack usage */
1457 register struct dcache *tdc;
1458 afs_size_t dirOffset, dirLen;
1459 struct VenusFid tfid;
1461 /* now we have to lookup the next fid */
1462 if (afs_InReadDir(adp))
1463 tdc = adp->dcreaddir;
1465 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq,
1466 &dirOffset, &dirLen, 1);
1468 *avcp = NULL; /* redundant, but harmless */
1473 /* now we will just call dir package with appropriate inode.
1474 * Dirs are always fetched in their entirety for now */
1475 ObtainReadLock(&adp->lock);
1476 ObtainReadLock(&tdc->lock);
1479 * Make sure that the data in the cache is current. There are two
1480 * cases we need to worry about:
1481 * 1. The cache data is being fetched by another process.
1482 * 2. The cache data is no longer valid
1484 * If a readdir is in progress _in this thread_, it has a shared
1485 * lock on the vcache and has obtained current data, so we just
1486 * use that. This eliminates several possible deadlocks.
1488 if (!afs_InReadDir(adp)) {
1489 while ((adp->f.states & CStatd)
1490 && (tdc->dflags & DFFetching)
1491 && hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
1492 ReleaseReadLock(&tdc->lock);
1493 ReleaseReadLock(&adp->lock);
1494 afs_osi_Sleep(&tdc->validPos);
1495 ObtainReadLock(&adp->lock);
1496 ObtainReadLock(&tdc->lock);
1498 if (!(adp->f.states & CStatd)
1499 || !hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
1500 ReleaseReadLock(&tdc->lock);
1501 ReleaseReadLock(&adp->lock);
1503 if (tname && tname != aname)
1504 osi_FreeLargeSpace(tname);
1509 /* Save the version number for when we call osi_dnlc_enter */
1510 hset(versionNo, tdc->f.versionNo);
1513 * check for, and handle "@sys" if it's there. We should be able
1514 * to avoid the alloc and the strcpy with a little work, but it's
1515 * not pressing. If there aren't any remote users (ie, via the
1516 * NFS translator), we have a slightly easier job.
1517 * the faster way to do this is to check for *aname == '@' and if
1518 * it's there, check for @sys, otherwise, assume there's no @sys
1519 * then, if the lookup fails, check for .*@sys...
1521 /* above now implemented by Check_AtSys and Next_AtSys */
1523 /* lookup the name in the appropriate dir, and return a cache entry
1524 * on the resulting fid */
1526 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1529 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1530 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
1532 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1534 tname = sysState.name;
1536 ReleaseReadLock(&tdc->lock);
1537 if (!afs_InReadDir(adp))
1540 if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1541 ReleaseReadLock(&adp->lock);
1543 if (tname[0] == '.')
1544 afs_LookupAFSDB(tname + 1);
1546 afs_LookupAFSDB(tname);
1547 if (tname && tname != aname)
1548 osi_FreeLargeSpace(tname);
1551 ReleaseReadLock(&adp->lock);
1554 /* new fid has same cell and volume */
1555 tfid.Cell = adp->f.fid.Cell;
1556 tfid.Fid.Volume = adp->f.fid.Fid.Volume;
1557 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1558 ICL_TYPE_STRING, tname, ICL_TYPE_FID, &tfid,
1559 ICL_TYPE_INT32, code);
1562 if (code != ENOENT) {
1563 printf("LOOKUP dirLookupOff -> %d\n", code);
1568 /* prefetch some entries, if the dir is currently open. The variable
1569 * dirCookie tells us where to start prefetching from.
1571 if (!AFS_IS_DISCONNECTED &&
1572 AFSDOBULK && adp->opens > 0 && !(adp->f.states & CForeign)
1573 && !afs_IsDynroot(adp) && !afs_InReadDir(adp)) {
1575 /* if the entry is not in the cache, or is in the cache,
1576 * but hasn't been statd, then do a bulk stat operation.
1580 ObtainReadLock(&afs_xvcache);
1581 tvc = afs_FindVCache(&tfid, &retry, 0 /* !stats,!lru */ );
1582 ReleaseReadLock(&afs_xvcache);
1583 } while (tvc && retry);
1585 if (!tvc || !(tvc->f.states & CStatd))
1586 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1590 /* if the vcache isn't usable, release it */
1591 if (tvc && !(tvc->f.states & CStatd)) {
1592 #ifndef AFS_FBSD80_ENV
1602 /* now get the status info, if we don't already have it */
1603 /* This is kind of weird, but we might wind up accidentally calling
1604 * RXAFS_Lookup because we happened upon a file which legitimately
1605 * has a 0 uniquifier. That is the result of allowing unique to wrap
1606 * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1607 * the file has not yet been looked up.
1610 afs_int32 cached = 0;
1611 if (!tfid.Fid.Unique && (adp->f.states & CForeign)) {
1612 tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
1614 if (!tvc && !bulkcode) { /* lookup failed or wasn't called */
1615 tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
1618 } /* sub-block just to reduce stack usage */
1621 if (adp->f.states & CForeign)
1622 tvc->f.states |= CForeign;
1623 tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
1624 tvc->f.parent.unique = adp->f.fid.Fid.Unique;
1625 tvc->f.states &= ~CBulkStat;
1627 if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
1628 ObtainSharedLock(&tvc->lock, 680);
1629 if (!tvc->linkData) {
1630 UpgradeSToWLock(&tvc->lock, 681);
1631 code = afs_HandleLink(tvc, &treq);
1632 ConvertWToRLock(&tvc->lock);
1634 ConvertSToRLock(&tvc->lock);
1637 if (!code && !afs_strchr(tvc->linkData, ':'))
1639 ReleaseReadLock(&tvc->lock);
1641 if (tvc->mvstat == 1 && (tvc->f.states & CMValid) && tvc->mvid != NULL)
1642 force_eval = 1; /* This is now almost for free, get it correct */
1644 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1645 if (!(flags & AFS_LOOKUP_NOEVAL))
1646 /* don't eval mount points */
1647 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1648 if (tvc->mvstat == 1 && force_eval) {
1649 /* a mt point, possibly unevaluated */
1650 struct volume *tvolp;
1652 ObtainWriteLock(&tvc->lock, 133);
1653 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1654 ReleaseWriteLock(&tvc->lock);
1657 #ifndef AFS_FBSD80_ENV
1661 afs_PutVolume(tvolp, WRITE_LOCK);
1665 /* next, we want to continue using the target of the mt point */
1666 if (tvc->mvid && (tvc->f.states & CMValid)) {
1668 /* now lookup target, to set .. pointer */
1669 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1670 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID,
1672 uvc = tvc; /* remember for later */
1674 if (tvolp && (tvolp->states & VForeign)) {
1675 /* XXXX tvolp has ref cnt on but not locked! XXX */
1677 afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
1679 tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
1681 #ifndef AFS_FBSD80_ENV
1682 afs_PutVCache(uvc); /* we're done with it */
1688 afs_PutVolume(tvolp, WRITE_LOCK);
1693 /* now, if we came via a new mt pt (say because of a new
1694 * release of a R/O volume), we must reevaluate the ..
1695 * ptr to point back to the appropriate place */
1697 ObtainWriteLock(&tvc->lock, 134);
1698 if (tvc->mvid == NULL) {
1699 tvc->mvid = (struct VenusFid *)
1700 osi_AllocSmallSpace(sizeof(struct VenusFid));
1702 /* setup backpointer */
1703 *tvc->mvid = tvolp->dotdot;
1704 ReleaseWriteLock(&tvc->lock);
1705 afs_PutVolume(tvolp, WRITE_LOCK);
1708 #ifndef AFS_FBSD80_ENV
1713 afs_PutVolume(tvolp, WRITE_LOCK);
1718 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1723 /* if we get here, we found something in a directory that couldn't
1724 * be located (a Multics "connection failure"). If the volume is
1725 * read-only, we try flushing this entry from the cache and trying
1727 if (!AFS_IS_DISCONNECTED) {
1730 tv = afs_GetVolume(&adp->f.fid, &treq, READ_LOCK);
1732 if (tv->states & VRO) {
1733 pass = 1; /* try this *once* */
1734 ObtainWriteLock(&afs_xcbhash, 495);
1735 afs_DequeueCallback(adp);
1736 /* re-stat to get later version */
1737 adp->f.states &= ~CStatd;
1738 ReleaseWriteLock(&afs_xcbhash);
1739 osi_dnlc_purgedp(adp);
1740 afs_PutVolume(tv, READ_LOCK);
1743 afs_PutVolume(tv, READ_LOCK);
1748 printf("Network down in afs_lookup\n");
1754 /* put the network buffer back, if need be */
1755 if (tname != aname && tname)
1756 osi_FreeLargeSpace(tname);
1759 /* Handle RENAME; only need to check rename "." */
1760 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1761 if (!FidCmp(&(tvc->f.fid), &(adp->f.fid))) {
1762 afs_PutVCache(*avcp);
1764 afs_PutFakeStat(&fakestate);
1765 return afs_CheckCode(EISDIR, &treq, 18);
1768 #endif /* AFS_OSF_ENV */
1771 afs_AddMarinerName(aname, tvc);
1773 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1774 if (!(flags & AFS_LOOKUP_NOEVAL))
1775 /* Here we don't enter the name into the DNLC because we want the
1776 * evaluated mount dir to be there (the vcache for the mounted volume)
1777 * rather than the vc of the mount point itself. we can still find the
1778 * mount point's vc in the vcache by its fid. */
1779 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1780 if (!hit && force_eval) {
1781 osi_dnlc_enter(adp, aname, tvc, &versionNo);
1783 #ifdef AFS_LINUX20_ENV
1784 /* So Linux inode cache is up to date. */
1785 code = afs_VerifyVCache(tvc, &treq);
1787 afs_PutFakeStat(&fakestate);
1788 AFS_DISCON_UNLOCK();
1789 return 0; /* can't have been any errors if hit and !code */
1796 code = afs_CheckCode(code, &treq, 19);
1798 /* If there is an error, make sure *avcp is null.
1799 * Alphas panic otherwise - defect 10719.
1804 afs_PutFakeStat(&fakestate);
1805 AFS_DISCON_UNLOCK();