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"
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/afs_stats.h" /* statistics */
23 #include "afs/afs_cbqueue.h"
24 #include "afs/nfsclient.h"
25 #include "afs/exporter.h"
26 #include "afs/afs_osidnlc.h"
27 #include "afs/afs_dynroot.h"
29 extern struct vcache *afs_globalVp;
31 afs_int32 afs_bkvolpref = 0;
32 afs_int32 afs_bulkStatsDone;
33 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
34 int afs_fakestat_enable = 0; /* 1: fakestat-all, 2: fakestat-crosscell */
37 /* this would be faster if it did comparison as int32word, but would be
38 * dependant on byte-order and alignment, and I haven't figured out
39 * what "@sys" is in binary... */
40 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
42 /* call under write lock, evaluate mvid field from a mt pt.
43 * avc is the vnode of the mount point object; must be write-locked.
44 * advc is the vnode of the containing directory (optional; if NULL and
45 * EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
46 * avolpp is where we return a pointer to the volume named by the mount pt, if success
47 * areq is the identity of the caller.
49 * NOTE: this function returns a held volume structure in *volpp if it returns 0!
52 EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
53 struct volume **avolpp, register struct vrequest *areq,
54 afs_uint32 *acellidxp, afs_uint32 *avolnump, afs_uint32 *avnoidp)
56 struct volume *tvp = 0;
59 char *cpos, *volnamep, *x;
61 afs_int32 prefetch; /* 1=>None 2=>RO 3=>BK */
62 afs_int32 mtptCell, assocCell = 0, hac = 0;
63 afs_int32 samecell, roname, len;
64 afs_uint32 volid, cellidx, vnoid = 0;
66 cpos = afs_strchr(data, ':'); /* if cell name present */
71 for (x = data; *x >= '0' && *x <= '9'; x++)
72 cellnum = (cellnum * 10) + (*x - '0');
74 tcell = afs_GetCell(cellnum, READ_LOCK);
76 tcell = afs_GetCellByName(data, READ_LOCK);
82 tcell = afs_GetCell(cellnum, READ_LOCK);
84 /*printf("No cellname %s , or cellnum %d , returning ENODEV\n",
89 /*printf("Lookup failed, returning ENODEV\n");*/
93 cellidx = tcell->cellIndex;
94 mtptCell = tcell->cellNum; /* The cell for the mountpoint */
96 hac = 1; /* has associated cell */
97 assocCell = tcell->lcellp->cellNum; /* The associated cell */
99 afs_PutCell(tcell, READ_LOCK);
101 cpos = afs_strrchr(volnamep, ':'); /* if vno present */
104 /* Look for an all-numeric volume ID */
106 for (x = volnamep; *x >= '0' && *x <= '9'; x++)
107 volid = (volid * 10) + (*x - '0');
111 if (!*x) /* allow vno with numeric volid only */
112 for (x = (cpos + 1); *x >= '0' && *x <= '9'; x++)
113 vnoid = (vnoid * 10) + (*x - '0');
119 * If the volume ID was all-numeric, and they didn't ask for a
120 * pointer to the volume structure, then just return the number
121 * as-is. This is currently only used for handling name lookups
122 * in the dynamic mount directory.
124 if (!*x && !avolpp) {
126 *acellidxp = cellidx;
135 * If the volume ID was all-numeric, and the type was '%', then
136 * assume whoever made the mount point knew what they were doing,
137 * and don't second-guess them by forcing use of a RW volume when
138 * they gave the ID of something else.
140 if (!*x && type == '%') {
141 tfid.Fid.Volume = volid; /* remember BK volume */
142 tfid.Cell = mtptCell;
143 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
145 /*printf("afs_GetVolume failed - returning ENODEV");*/
146 return ENODEV; /* oops, can't do it */
151 /* Is volume name a "<n>.backup" or "<n>.readonly" name */
152 len = strlen(volnamep);
153 roname = ((len > 9) && (strcmp(&volnamep[len - 9], ".readonly") == 0))
154 || ((len > 7) && (strcmp(&volnamep[len - 7], ".backup") == 0));
156 /* When we cross mountpoint, do we stay in the same cell */
157 samecell = (cellnum == mtptCell) || (hac && (cellnum == assocCell));
159 /* Decide whether to prefetch the BK, or RO. Also means we want the BK or
161 * If this is a regular mountpoint with a RW volume name
162 * - If BK preference is enabled AND we remain within the same cell AND
163 * start from a BK volume, then we will want to prefetch the BK volume.
164 * - If we cross a cell boundary OR start from a RO volume, then we will
165 * want to prefetch the RO volume.
167 if ((type == '#') && !roname) {
168 if (afs_bkvolpref && samecell && (states & CBackup))
169 prefetch = 3; /* Prefetch the BK */
170 else if (!samecell || (states & CRO))
171 prefetch = 2; /* Prefetch the RO */
173 prefetch = 1; /* Do not prefetch */
175 prefetch = 1; /* Do not prefetch */
178 /* Get the volume struct. Unless this volume name has ".readonly" or
179 * ".backup" in it, this will get the volume struct for the RW volume.
180 * The RO volume will be prefetched if requested (but not returned).
182 /*printf("Calling GetVolumeByName\n");*/
183 tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK);
185 /* If no volume was found in this cell, try the associated linked cell */
186 if (!tvp && hac && areq->volumeError) {
188 afs_GetVolumeByName(volnamep, assocCell, prefetch, areq,
192 /* Still not found. If we are looking for the RO, then perhaps the RW
193 * doesn't exist? Try adding ".readonly" to volname and look for that.
194 * Don't know why we do this. Would have still found it in above call - jpm.
196 if (!tvp && (prefetch == 2) && len < AFS_SMALLOCSIZ - 10) {
197 buf = (char *)osi_AllocSmallSpace(len + 10);
199 strcpy(buf, volnamep);
200 afs_strcat(buf, ".readonly");
202 tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
204 /* Try the associated linked cell if failed */
205 if (!tvp && hac && areq->volumeError) {
206 tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
208 osi_FreeSmallSpace(buf);
212 /*printf("Couldn't find the volume\n");*/
213 return ENODEV; /* Couldn't find the volume */
216 /* Don't cross mountpoint from a BK to a BK volume */
217 if ((states & CBackup) && (tvp->states & VBackup)) {
218 afs_PutVolume(tvp, WRITE_LOCK);
222 /* If we want (prefetched) the BK and it exists, then drop the RW volume
224 * Otherwise, if we want (prefetched0 the RO and it exists, then drop the
225 * RW volume and get the RO.
226 * Otherwise, go with the RW.
228 if ((prefetch == 3) && tvp->backVol) {
229 tfid.Fid.Volume = tvp->backVol; /* remember BK volume */
230 tfid.Cell = tvp->cell;
231 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
232 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
234 return ENODEV; /* oops, can't do it */
235 } else if ((prefetch >= 2) && tvp->roVol) {
236 tfid.Fid.Volume = tvp->roVol; /* remember RO volume */
237 tfid.Cell = tvp->cell;
238 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
239 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
241 return ENODEV; /* oops, can't do it */
246 *acellidxp = cellidx;
248 *avolnump = tvp->volume;
254 afs_PutVolume(tvp, WRITE_LOCK);
259 EvalMountPoint(register struct vcache *avc, struct vcache *advc,
260 struct volume **avolpp, register struct vrequest *areq)
265 AFS_STATCNT(EvalMountPoint);
267 if (avc->mvid && (avc->f.states & CMValid))
268 return 0; /* done while racing */
271 code = afs_HandleLink(avc, areq);
275 /* Determine which cell and volume the mointpoint goes to */
276 code = EvalMountData(avc->linkData[0], avc->linkData + 1,
277 avc->f.states, avc->f.fid.Cell, avolpp, areq, 0, 0,
279 if (code) return code;
286 (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid));
287 avc->mvid->Cell = (*avolpp)->cell;
288 avc->mvid->Fid.Volume = (*avolpp)->volume;
289 avc->mvid->Fid.Vnode = avnoid;
290 avc->mvid->Fid.Unique = 1;
291 avc->f.states |= CMValid;
293 /* Used to: if the mount point is stored within a backup volume,
294 * then we should only update the parent pointer information if
295 * there's none already set, so as to avoid updating a volume's ..
296 * info with something in an OldFiles directory.
298 * Next two lines used to be under this if:
300 * if (!(avc->f.states & CBackup) || tvp->dotdot.Fid.Volume == 0)
302 * Now: update mount point back pointer on every call, so that we handle
303 * multiple mount points better. This way, when du tries to go back
304 * via chddir(".."), it will end up exactly where it started, yet
305 * cd'ing via a new path to a volume will reset the ".." pointer
308 (*avolpp)->mtpoint = avc->f.fid; /* setup back pointer to mtpoint */
311 (*avolpp)->dotdot = advc->f.fid;
319 * Must be called on an afs_fakestat_state object before calling
320 * afs_EvalFakeStat or afs_PutFakeStat. Calling afs_PutFakeStat
321 * without calling afs_EvalFakeStat is legal, as long as this
322 * function is called.
325 afs_InitFakeStat(struct afs_fakestat_state *state)
327 if (!afs_fakestat_enable)
332 state->need_release = 0;
336 * afs_EvalFakeStat_int
338 * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
339 * which is called by those wrapper functions.
341 * Only issues RPCs if canblock is non-zero.
344 afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
345 struct vrequest *areq, int canblock)
347 struct vcache *tvc, *root_vp;
348 struct volume *tvolp = NULL;
351 if (!afs_fakestat_enable)
354 osi_Assert(state->valid == 1);
355 osi_Assert(state->did_eval == 0);
359 if (tvc->mvstat != 1)
362 /* Is the call to VerifyVCache really necessary? */
363 code = afs_VerifyVCache(tvc, areq);
367 ObtainWriteLock(&tvc->lock, 599);
368 code = EvalMountPoint(tvc, NULL, &tvolp, areq);
369 ReleaseWriteLock(&tvc->lock);
373 tvolp->dotdot = tvc->f.fid;
374 tvolp->dotdot.Fid.Vnode = tvc->f.parent.vnode;
375 tvolp->dotdot.Fid.Unique = tvc->f.parent.unique;
378 if (tvc->mvid && (tvc->f.states & CMValid)) {
384 ObtainWriteLock(&afs_xvcache, 597);
385 root_vp = afs_FindVCache(tvc->mvid, &retry, IS_WLOCK);
386 if (root_vp && retry) {
387 ReleaseWriteLock(&afs_xvcache);
388 afs_PutVCache(root_vp);
390 } while (root_vp && retry);
391 ReleaseWriteLock(&afs_xvcache);
393 root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
396 code = canblock ? ENOENT : 0;
399 #ifdef AFS_DARWIN80_ENV
400 root_vp->f.m.Type = VDIR;
402 code = afs_darwin_finalizevnode(root_vp, NULL, NULL, 0);
405 vnode_ref(AFSTOV(root_vp));
407 if (tvolp && !afs_InReadDir(root_vp)) {
408 /* Is this always kosher? Perhaps we should instead use
409 * NBObtainWriteLock to avoid potential deadlock.
411 ObtainWriteLock(&root_vp->lock, 598);
413 root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
414 *root_vp->mvid = tvolp->dotdot;
415 ReleaseWriteLock(&root_vp->lock);
417 state->need_release = 1;
418 state->root_vp = root_vp;
422 code = canblock ? ENOENT : 0;
427 afs_PutVolume(tvolp, WRITE_LOCK);
434 * Automatically does the equivalent of EvalMountPoint for vcache entries
435 * which are mount points. Remembers enough state to properly release
436 * the volume root vcache when afs_PutFakeStat() is called.
438 * State variable must be initialized by afs_InitFakeState() beforehand.
440 * Returns 0 when everything succeeds and *avcp points to the vcache entry
441 * that should be used for the real vnode operation. Returns non-zero if
442 * something goes wrong and the error code should be returned to the user.
445 afs_EvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
446 struct vrequest *areq)
448 return afs_EvalFakeStat_int(avcp, state, areq, 1);
452 * afs_TryEvalFakeStat
454 * Same as afs_EvalFakeStat, but tries not to talk to remote servers
455 * and only evaluate the mount point if all the data is already in
458 * Returns 0 if everything succeeds and *avcp points to a valid
459 * vcache entry (possibly evaluated).
462 afs_TryEvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
463 struct vrequest *areq)
465 return afs_EvalFakeStat_int(avcp, state, areq, 0);
471 * Perform any necessary cleanup at the end of a vnode op, given that
472 * afs_InitFakeStat was previously called with this state.
475 afs_PutFakeStat(struct afs_fakestat_state *state)
477 if (!afs_fakestat_enable)
480 osi_Assert(state->valid == 1);
481 if (state->need_release)
482 afs_PutVCache(state->root_vp);
487 afs_ENameOK(register char *aname)
491 AFS_STATCNT(ENameOK);
492 tlen = strlen(aname);
493 if (tlen >= 4 && strcmp(aname + tlen - 4, "@sys") == 0)
499 afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
500 register char *bufp, int *num, char **sysnamelist[])
502 register struct unixuser *au;
503 register afs_int32 error;
505 AFS_STATCNT(getsysname);
507 *sysnamelist = afs_sysnamelist;
509 if (!afs_nfsexporter)
510 strcpy(bufp, (*sysnamelist)[0]);
512 au = afs_GetUser(areq->uid, adp->f.fid.Cell, 0);
514 error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
516 strcpy(bufp, "@sys");
520 strcpy(bufp, (*sysnamelist)[0]);
523 strcpy(bufp, afs_sysname);
530 Check_AtSys(register struct vcache *avc, const char *aname,
531 struct sysname_info *state, struct vrequest *areq)
534 char **sysnamelist[MAXNUMSYSNAMES];
536 if (AFS_EQ_ATSYS(aname)) {
538 state->name = (char *)osi_AllocLargeSpace(MAXSYSNAME);
541 afs_getsysname(areq, avc, state->name, &num, sysnamelist);
546 state->name = (char *)aname;
551 Next_AtSys(register struct vcache *avc, struct vrequest *areq,
552 struct sysname_info *state)
554 int num = afs_sysnamecount;
555 char **sysnamelist[MAXNUMSYSNAMES];
557 if (state->index == -1)
558 return 0; /* No list */
560 /* Check for the initial state of aname != "@sys" in Check_AtSys */
561 if (state->offset == -1 && state->allocked == 0) {
562 register char *tname;
564 /* Check for .*@sys */
565 for (tname = state->name; *tname; tname++)
566 /*Move to the end of the string */ ;
568 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
569 state->offset = (tname - 4) - state->name;
570 tname = (char *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
571 strncpy(tname, state->name, state->offset);
576 afs_getsysname(areq, avc, state->name + state->offset, &num,
580 return 0; /* .*@sys doesn't match either */
582 register struct unixuser *au;
583 register afs_int32 error;
585 *sysnamelist = afs_sysnamelist;
587 if (afs_nfsexporter) {
588 au = afs_GetUser(areq->uid, avc->f.fid.Cell, 0);
591 EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
599 if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
600 return 0; /* end of list */
602 strcpy(state->name + state->offset, (*sysnamelist)[(unsigned int)state->index]);
606 extern int BlobScan(struct dcache * afile, afs_int32 ablob);
608 /* called with an unlocked directory and directory cookie. Areqp
609 * describes who is making the call.
610 * Scans the next N (about 30, typically) directory entries, and does
611 * a bulk stat call to stat them all.
613 * Must be very careful when merging in RPC responses, since we dont
614 * want to overwrite newer info that was added by a file system mutating
615 * call that ran concurrently with our bulk stat call.
617 * We do that, as described below, by not merging in our info (always
618 * safe to skip the merge) if the status info is valid in the vcache entry.
620 * If adapt ever implements the bulk stat RPC, then this code will need to
621 * ensure that vcaches created for failed RPC's to older servers have the
624 static struct vcache *BStvc = NULL;
627 afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
629 int nentries; /* # of entries to prefetch */
630 int nskip; /* # of slots in the LRU queue to skip */
631 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
632 struct dcache *dcp; /* chunk containing the dir block */
633 afs_size_t temp; /* temp for holding chunk length, &c. */
634 struct AFSFid *fidsp; /* file IDs were collecting */
635 struct AFSCallBack *cbsp; /* call back pointers */
636 struct AFSCallBack *tcbp; /* temp callback ptr */
637 struct AFSFetchStatus *statsp; /* file status info */
638 struct AFSVolSync volSync; /* vol sync return info */
639 struct vcache *tvcp; /* temp vcp */
640 struct afs_q *tq; /* temp queue variable */
641 AFSCBFids fidParm; /* file ID parm for bulk stat */
642 AFSBulkStats statParm; /* stat info parm for bulk stat */
643 int fidIndex = 0; /* which file were stating */
644 struct afs_conn *tcp = 0; /* conn for call */
645 AFSCBs cbParm; /* callback parm for bulk stat */
646 struct server *hostp = 0; /* host we got callback from */
647 long startTime; /* time we started the call,
648 * for callback expiration base
650 afs_size_t statSeqNo = 0; /* Valued of file size to detect races */
651 int code; /* error code */
652 long newIndex; /* new index in the dir */
653 struct DirEntry *dirEntryp; /* dir entry we are examining */
655 struct VenusFid afid; /* file ID we are using now */
656 struct VenusFid tfid; /* another temp. file ID */
657 afs_int32 retry; /* handle low-level SGI MP race conditions */
658 long volStates; /* flags from vol structure */
659 struct volume *volp = 0; /* volume ptr */
660 struct VenusFid dotdot = {0, {0, 0, 0}};
661 int flagIndex = 0; /* First file with bulk fetch flag set */
662 int inlinebulk = 0; /* Did we use InlineBulk RPC or not? */
665 dotdot.Fid.Unique = 0;
666 dotdot.Fid.Vnode = 0;
667 #ifdef AFS_DARWIN80_ENV
668 panic("bulkstatus doesn't work on AFS_DARWIN80_ENV. don't call it");
670 /* first compute some basic parameters. We dont want to prefetch more
671 * than a fraction of the cache in any given call, and we want to preserve
672 * a portion of the LRU queue in any event, so as to avoid thrashing
673 * the entire stat cache (we will at least leave some of it alone).
674 * presently dont stat more than 1/8 the cache in any one call. */
675 nentries = afs_cacheStats / 8;
677 /* dont bother prefetching more than one calls worth of info */
678 if (nentries > AFSCBMAX)
681 /* heuristic to make sure that things fit in 4K. This means that
682 * we shouldnt make it any bigger than 47 entries. I am typically
683 * going to keep it a little lower, since we don't want to load
684 * too much of the stat cache.
689 /* now, to reduce the stack size, well allocate two 4K blocks,
690 * one for fids and callbacks, and one for stat info. Well set
691 * up our pointers to the memory from there, too.
693 statsp = (AFSFetchStatus *)
694 osi_Alloc(AFSCBMAX * sizeof(AFSFetchStatus));
695 fidsp = (AFSFid *) osi_AllocLargeSpace(nentries * sizeof(AFSFid));
696 cbsp = (AFSCallBack *)
697 osi_Alloc(AFSCBMAX * sizeof(AFSCallBack));
699 /* next, we must iterate over the directory, starting from the specified
700 * cookie offset (dirCookie), and counting out nentries file entries.
701 * We skip files that already have stat cache entries, since we
702 * dont want to bulk stat files that are already in the cache.
705 code = afs_VerifyVCache(adp, areqp);
709 dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
715 /* lock the directory cache entry */
716 ObtainReadLock(&adp->lock);
717 ObtainReadLock(&dcp->lock);
720 * Make sure that the data in the cache is current. There are two
721 * cases we need to worry about:
722 * 1. The cache data is being fetched by another process.
723 * 2. The cache data is no longer valid
725 while ((adp->f.states & CStatd)
726 && (dcp->dflags & DFFetching)
727 && hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
728 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
729 __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, dcp,
730 ICL_TYPE_INT32, dcp->dflags);
731 ReleaseReadLock(&dcp->lock);
732 ReleaseReadLock(&adp->lock);
733 afs_osi_Sleep(&dcp->validPos);
734 ObtainReadLock(&adp->lock);
735 ObtainReadLock(&dcp->lock);
737 if (!(adp->f.states & CStatd)
738 || !hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
739 ReleaseReadLock(&dcp->lock);
740 ReleaseReadLock(&adp->lock);
745 /* Generate a sequence number so we can tell whether we should
746 * store the attributes when processing the response. This number is
747 * stored in the file size when we set the CBulkFetching bit. If the
748 * CBulkFetching is still set and this value hasn't changed, then
749 * we know we were the last to set CBulkFetching bit for this file,
750 * and it is safe to set the status information for this file.
752 statSeqNo = bulkStatCounter++;
754 /* now we have dir data in the cache, so scan the dir page */
757 while (1) { /* Should probably have some constant bound */
758 /* look for first safe entry to examine in the directory. BlobScan
759 * looks for a the 1st allocated dir after the dirCookie slot.
761 newIndex = BlobScan(dcp, (dirCookie >> 5));
765 /* remember the updated directory cookie */
766 dirCookie = newIndex << 5;
768 /* get a ptr to the dir entry */
770 (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
774 /* dont copy more than we have room for */
775 if (fidIndex >= nentries) {
776 DRelease(dirEntryp, 0);
780 /* now, if the dir entry looks good, copy it out to our list. Vnode
781 * 0 means deleted, although it should also be free were it deleted.
783 if (dirEntryp->fid.vnode != 0) {
784 /* dont copy entries we have in our cache. This check will
785 * also make us skip "." and probably "..", unless it has
786 * disappeared from the cache since we did our namei call.
788 tfid.Cell = adp->f.fid.Cell;
789 tfid.Fid.Volume = adp->f.fid.Fid.Volume;
790 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
791 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
794 ObtainWriteLock(&afs_xvcache, 130);
795 tvcp = afs_FindVCache(&tfid, &retry, IS_WLOCK /* no stats | LRU */ );
797 ReleaseWriteLock(&afs_xvcache);
800 } while (tvcp && retry);
801 if (!tvcp) { /* otherwise, create manually */
802 tvcp = afs_NewVCache(&tfid, hostp);
805 ObtainWriteLock(&tvcp->lock, 505);
806 ReleaseWriteLock(&afs_xvcache);
807 afs_RemoveVCB(&tfid);
808 ReleaseWriteLock(&tvcp->lock);
810 ReleaseWriteLock(&afs_xvcache);
813 ReleaseWriteLock(&afs_xvcache);
817 DRelease(dirEntryp, 0);
818 ReleaseReadLock(&dcp->lock);
819 ReleaseReadLock(&adp->lock);
821 goto done; /* can happen if afs_NewVCache fails */
824 #ifdef AFS_DARWIN80_ENV
825 if (tvcp->f.states & CVInit) {
826 /* XXX don't have status yet, so creating the vnode is
827 not yet useful. we would get CDeadVnode set, and the
828 upcoming PutVCache will cause the vcache to be flushed &
829 freed, which in turn means the bulkstatus results won't
833 /* WARNING: afs_DoBulkStat uses the Length field to store a
834 * sequence number for each bulk status request. Under no
835 * circumstances should afs_DoBulkStat store a sequence number
836 * if the new length will be ignored when afs_ProcessFS is
837 * called with new stats. */
839 if (!(tvcp->f.states & (CStatd | CBulkFetching))
840 && (tvcp->execsOrWriters <= 0)
841 && !afs_DirtyPages(tvcp)
842 && !AFS_VN_MAPPED((vnode_t *) tvcp))
844 if (!(tvcp->f.states & (CStatd | CBulkFetching))
845 && (tvcp->execsOrWriters <= 0)
846 && !afs_DirtyPages(tvcp))
850 /* this entry doesnt exist in the cache, and is not
851 * already being fetched by someone else, so add it to the
852 * list of file IDs to obtain.
854 * We detect a callback breaking race condition by checking the
855 * CBulkFetching state bit and the value in the file size.
856 * It is safe to set the status only if the CBulkFetching
857 * flag is still set and the value in the file size does
860 * Don't fetch status for dirty files. We need to
861 * preserve the value of the file size. We could
862 * flush the pages, but it wouldn't be worthwhile.
864 memcpy((char *)(fidsp + fidIndex), (char *)&tfid.Fid,
866 tvcp->f.states |= CBulkFetching;
867 tvcp->f.m.Length = statSeqNo;
873 /* if dir vnode has non-zero entry */
874 /* move to the next dir entry by adding in the # of entries
875 * used by this dir entry.
877 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
878 DRelease(dirEntryp, 0);
882 } /* while loop over all dir entries */
884 /* now release the dir lock and prepare to make the bulk RPC */
885 ReleaseReadLock(&dcp->lock);
886 ReleaseReadLock(&adp->lock);
888 /* release the chunk */
891 /* dont make a null call */
896 /* setup the RPC parm structures */
897 fidParm.AFSCBFids_len = fidIndex;
898 fidParm.AFSCBFids_val = fidsp;
899 statParm.AFSBulkStats_len = fidIndex;
900 statParm.AFSBulkStats_val = statsp;
901 cbParm.AFSCBs_len = fidIndex;
902 cbParm.AFSCBs_val = cbsp;
904 /* start the timer; callback expirations are relative to this */
905 startTime = osi_Time();
907 tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK);
909 hostp = tcp->srvr->server;
910 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
913 if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
915 RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
917 if (code == RXGEN_OPCODE) {
918 tcp->srvr->server->flags |= SNO_INLINEBULK;
921 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
928 RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
936 (tcp, code, &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
939 /* now, if we didnt get the info, bail out. */
943 /* we need vol flags to create the entries properly */
944 dotdot.Fid.Volume = 0;
945 volp = afs_GetVolume(&adp->f.fid, areqp, READ_LOCK);
947 volStates = volp->states;
948 if (volp->dotdot.Fid.Volume != 0)
949 dotdot = volp->dotdot;
953 /* find the place to merge the info into We do this by skipping
954 * nskip entries in the LRU queue. The more we skip, the more
955 * we preserve, since the head of the VLRU queue is the most recently
959 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
960 ObtainReadLock(&afs_xvcache);
962 /* actually a serious error, probably should panic. Probably will
963 * panic soon, oh well. */
964 ReleaseReadLock(&afs_xvcache);
965 afs_warnuser("afs_DoBulkStat: VLRU empty!");
968 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
969 refpanic("Bulkstat VLRU inconsistent");
971 for (tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
974 else if (QNext(QPrev(tq)) != tq) {
976 refpanic("BulkStat VLRU inconsistent");
982 lruvcp = QTOV(VLRU.next);
984 /* now we have to hold this entry, so that it does not get moved
985 * into the free list while we're running. It could still get
986 * moved within the lru queue, but hopefully that will be rare; it
987 * doesn't hurt nearly as much.
990 osi_vnhold(lruvcp, &retry);
991 ReleaseReadLock(&afs_xvcache); /* could be read lock */
995 /* otherwise, merge in the info. We have to be quite careful here,
996 * since we need to ensure that we don't merge old info over newer
997 * stuff in a stat cache entry. We're very conservative here: we don't
998 * do the merge at all unless we ourselves create the stat cache
999 * entry. That's pretty safe, and should work pretty well, since we
1000 * typically expect to do the stat cache creation ourselves.
1002 * We also have to take into account racing token revocations.
1004 for (i = 0; i < fidIndex; i++) {
1005 if ((&statsp[i])->errorCode)
1007 afid.Cell = adp->f.fid.Cell;
1008 afid.Fid.Volume = adp->f.fid.Fid.Volume;
1009 afid.Fid.Vnode = fidsp[i].Vnode;
1010 afid.Fid.Unique = fidsp[i].Unique;
1013 ObtainReadLock(&afs_xvcache);
1014 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1015 ReleaseReadLock(&afs_xvcache);
1016 } while (tvcp && retry);
1018 /* The entry may no longer exist */
1023 /* now we have the entry held, but we need to fill it in */
1024 ObtainWriteLock(&tvcp->lock, 131);
1026 /* if CBulkFetching is not set, or if the file size no longer
1027 * matches the value we placed there when we set the CBulkFetching
1028 * flag, then someone else has done something with this node,
1029 * and we may not have the latest status information for this
1030 * file. Leave the entry alone.
1032 if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
1034 ReleaseWriteLock(&tvcp->lock);
1035 afs_PutVCache(tvcp);
1039 /* now copy ".." entry back out of volume structure, if necessary */
1040 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
1042 tvcp->mvid = (struct VenusFid *)
1043 osi_AllocSmallSpace(sizeof(struct VenusFid));
1044 *tvcp->mvid = dotdot;
1047 ObtainWriteLock(&afs_xvcache, 132);
1048 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1049 refpanic("Bulkstat VLRU inconsistent2");
1051 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1052 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1053 refpanic("Bulkstat VLRU inconsistent4");
1055 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1056 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1057 refpanic("Bulkstat VLRU inconsistent5");
1060 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
1061 QRemove(&tvcp->vlruq);
1062 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
1065 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
1066 refpanic("Bulkstat VLRU inconsistent3");
1068 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
1069 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq)) {
1070 refpanic("Bulkstat VLRU inconsistent5");
1072 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
1073 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq)) {
1074 refpanic("Bulkstat VLRU inconsistent6");
1076 ReleaseWriteLock(&afs_xvcache);
1078 ObtainWriteLock(&afs_xcbhash, 494);
1080 /* We need to check the flags again. We may have missed
1081 * something while we were waiting for a lock.
1083 if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
1085 ReleaseWriteLock(&tvcp->lock);
1086 ReleaseWriteLock(&afs_xcbhash);
1087 afs_PutVCache(tvcp);
1091 /* now merge in the resulting status back into the vnode.
1092 * We only do this if the entry looks clear.
1094 afs_ProcessFS(tvcp, &statsp[i], areqp);
1095 #if defined(AFS_LINUX22_ENV)
1096 afs_fill_inode(AFSTOV(tvcp), NULL); /* reset inode operations */
1099 /* do some accounting for bulk stats: mark this entry as
1100 * loaded, so we can tell if we use it before it gets
1103 tvcp->f.states |= CBulkStat;
1104 tvcp->f.states &= ~CBulkFetching;
1106 afs_bulkStatsDone++;
1108 /* merge in vol info */
1109 if (volStates & VRO)
1110 tvcp->f.states |= CRO;
1111 if (volStates & VBackup)
1112 tvcp->f.states |= CBackup;
1113 if (volStates & VForeign)
1114 tvcp->f.states |= CForeign;
1116 /* merge in the callback info */
1117 tvcp->f.states |= CTruth;
1119 /* get ptr to the callback we are interested in */
1122 if (tcbp->ExpirationTime != 0) {
1123 tvcp->cbExpires = tcbp->ExpirationTime + startTime;
1124 tvcp->callback = hostp;
1125 tvcp->f.states |= CStatd;
1126 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
1127 } else if (tvcp->f.states & CRO) {
1128 /* ordinary callback on a read-only volume -- AFS 3.2 style */
1129 tvcp->cbExpires = 3600 + startTime;
1130 tvcp->callback = hostp;
1131 tvcp->f.states |= CStatd;
1132 afs_QueueCallback(tvcp, CBHash(3600), volp);
1135 tvcp->f.states &= ~(CStatd | CUnique);
1136 afs_DequeueCallback(tvcp);
1137 if ((tvcp->f.states & CForeign) || (vType(tvcp) == VDIR))
1138 osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */
1140 ReleaseWriteLock(&afs_xcbhash);
1142 ReleaseWriteLock(&tvcp->lock);
1143 /* finally, we're done with the entry */
1144 afs_PutVCache(tvcp);
1145 } /* for all files we got back */
1147 /* finally return the pointer into the LRU queue */
1148 afs_PutVCache(lruvcp);
1151 /* Be sure to turn off the CBulkFetching flags */
1152 for (i = flagIndex; i < fidIndex; i++) {
1153 afid.Cell = adp->f.fid.Cell;
1154 afid.Fid.Volume = adp->f.fid.Fid.Volume;
1155 afid.Fid.Vnode = fidsp[i].Vnode;
1156 afid.Fid.Unique = fidsp[i].Unique;
1159 ObtainReadLock(&afs_xvcache);
1160 tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
1161 ReleaseReadLock(&afs_xvcache);
1162 } while (tvcp && retry);
1163 if (tvcp != NULL && (tvcp->f.states & CBulkFetching)
1164 && (tvcp->f.m.Length == statSeqNo)) {
1165 tvcp->f.states &= ~CBulkFetching;
1168 afs_PutVCache(tvcp);
1172 afs_PutVolume(volp, READ_LOCK);
1174 /* If we did the InlineBulk RPC pull out the return code */
1175 if (inlinebulk && code == 0) {
1176 if ((&statsp[0])->errorCode) {
1177 afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->f.fid, areqp,
1178 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL);
1179 code = (&statsp[0])->errorCode;
1185 osi_FreeLargeSpace((char *)fidsp);
1186 osi_Free((char *)statsp, AFSCBMAX * sizeof(AFSFetchStatus));
1187 osi_Free((char *)cbsp, AFSCBMAX * sizeof(AFSCallBack));
1191 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
1192 #ifdef AFS_DARWIN80_ENV
1195 static int AFSDOBULK = 1;
1200 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, AFS_UCRED *acred, int opflag, int wantparent)
1201 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
1202 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, struct pathname *pnp, int flags, struct vnode *rdir, AFS_UCRED *acred)
1203 #elif defined(UKERNEL)
1204 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, AFS_UCRED *acred, int flags)
1206 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, AFS_UCRED *acred)
1209 struct vrequest treq;
1211 register struct vcache *tvc = 0;
1212 register afs_int32 code;
1213 register afs_int32 bulkcode = 0;
1214 int pass = 0, hit = 0;
1215 int force_eval = afs_fakestat_enable ? 0 : 1;
1217 extern afs_int32 afs_mariner; /*Writing activity to log? */
1218 afs_hyper_t versionNo;
1219 int no_read_access = 0;
1220 struct sysname_info sysState; /* used only for @sys checking */
1221 int dynrootRetry = 1;
1222 struct afs_fakestat_state fakestate;
1223 int tryEvalOnly = 0;
1224 OSI_VC_CONVERT(adp);
1226 AFS_STATCNT(afs_lookup);
1227 afs_InitFakeStat(&fakestate);
1231 if ((code = afs_InitReq(&treq, acred)))
1235 ndp->ni_dvp = AFSTOV(adp);
1236 #endif /* AFS_OSF_ENV */
1238 if (afs_fakestat_enable && adp->mvstat == 1) {
1239 if (strcmp(aname, ".directory") == 0)
1243 #if defined(AFS_DARWIN_ENV)
1244 /* Workaround for MacOSX Finder, which tries to look for
1245 * .DS_Store and Contents under every directory.
1247 if (afs_fakestat_enable && adp->mvstat == 1) {
1248 if (strcmp(aname, ".DS_Store") == 0)
1250 if (strcmp(aname, "Contents") == 0)
1256 code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
1258 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
1260 /*printf("Code is %d\n", code);*/
1262 if (tryEvalOnly && adp->mvstat == 1)
1267 *avcp = NULL; /* Since some callers don't initialize it */
1269 /* come back to here if we encounter a non-existent object in a read-only
1270 * volume's directory */
1273 *avcp = NULL; /* Since some callers don't initialize it */
1276 if (!(adp->f.states & CStatd) && !afs_InReadDir(adp)) {
1277 if ((code = afs_VerifyVCache2(adp, &treq))) {
1283 /* watch for ".." in a volume root */
1284 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1285 /* looking up ".." in root via special hacks */
1286 if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
1288 if (adp == afs_globalVp) {
1289 struct vnode *rvp = AFSTOV(adp);
1291 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
1292 ndp->ni_dvp = ndp->ni_vp;
1302 /* otherwise we have the fid here, so we use it */
1303 /*printf("Getting vcache\n");*/
1304 tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
1305 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
1306 ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
1308 code = (tvc ? 0 : ENOENT);
1310 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1314 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code); */
1319 /* now check the access */
1320 if (treq.uid != adp->last_looker) {
1321 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1326 adp->last_looker = treq.uid;
1329 /* Check for read access as well. We need read access in order to
1330 * stat files, but not to stat subdirectories. */
1331 if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
1334 /* special case lookup of ".". Can we check for it sooner in this code,
1335 * for instance, way up before "redo:" ??
1336 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
1337 * invent a lightweight version of GetVCache.
1339 if (aname[0] == '.' && !aname[1]) { /* special case */
1340 ObtainReadLock(&afs_xvcache);
1342 ReleaseReadLock(&afs_xvcache);
1343 #ifdef AFS_DARWIN80_ENV
1344 vnode_get(AFSTOV(adp));
1349 if (adp && !VREFCOUNT_GT(adp, 0)) {
1356 * Special case lookup of ".." in the dynamic mount directory.
1357 * The parent of this directory is _always_ the AFS root volume.
1359 if (afs_IsDynrootMount(adp) &&
1360 aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1362 ObtainReadLock(&afs_xvcache);
1363 osi_vnhold(afs_globalVp, 0);
1364 ReleaseReadLock(&afs_xvcache);
1365 #ifdef AFS_DARWIN80_ENV
1366 vnode_get(AFSTOV(afs_globalVp));
1369 *avcp = tvc = afs_globalVp;
1375 * Special case lookups in the dynamic mount directory.
1376 * The names here take the form cell:volume, similar to a mount point.
1377 * EvalMountData parses that and returns a cell and volume ID, which
1378 * we use to construct the appropriate dynroot Fid.
1380 if (afs_IsDynrootMount(adp)) {
1381 struct VenusFid tfid;
1382 afs_uint32 cellidx, volid, vnoid;
1384 code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid);
1387 afs_GetDynrootMountFid(&tfid);
1388 tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
1389 tfid.Fid.Unique = volid;
1390 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1395 #ifdef AFS_LINUX26_ENV
1397 * Special case of the dynamic mount volume in a static root.
1398 * This is really unfortunate, but we need this for the translator.
1400 if (adp == afs_globalVp && !afs_GetDynrootEnable() &&
1401 !strcmp(aname, AFS_DYNROOT_MOUNTNAME)) {
1402 struct VenusFid tfid;
1404 afs_GetDynrootMountFid(&tfid);
1405 *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
1412 Check_AtSys(adp, aname, &sysState, &treq);
1413 tname = sysState.name;
1415 /* 1st Check_AtSys and lookup by tname is required here, for now,
1416 * because the dnlc is *not* told to remove entries for the parent
1417 * dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1418 * if the cached entry for the parent dir is invalidated for a
1420 * Otherwise, we'd be able to do a dnlc lookup on an entry ending
1421 * w/@sys and know the dnlc was consistent with reality. */
1422 tvc = osi_dnlc_lookup(adp, tname, WRITE_LOCK);
1423 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1425 if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1426 /* need read access on dir to stat non-directory / non-link */
1427 #ifndef AFS_FBSD80_ENV
1434 #ifdef AFS_LINUX22_ENV
1435 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1436 AFS_RELE(AFSTOV(tvc));
1443 #else /* non - LINUX */
1447 #endif /* linux22 */
1450 { /* sub-block just to reduce stack usage */
1451 register struct dcache *tdc;
1452 afs_size_t dirOffset, dirLen;
1453 struct VenusFid tfid;
1455 /* now we have to lookup the next fid */
1456 if (afs_InReadDir(adp))
1457 tdc = adp->dcreaddir;
1459 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq,
1460 &dirOffset, &dirLen, 1);
1462 *avcp = NULL; /* redundant, but harmless */
1467 /* now we will just call dir package with appropriate inode.
1468 * Dirs are always fetched in their entirety for now */
1469 ObtainReadLock(&adp->lock);
1470 ObtainReadLock(&tdc->lock);
1473 * Make sure that the data in the cache is current. There are two
1474 * cases we need to worry about:
1475 * 1. The cache data is being fetched by another process.
1476 * 2. The cache data is no longer valid
1478 * If a readdir is in progress _in this thread_, it has a shared
1479 * lock on the vcache and has obtained current data, so we just
1480 * use that. This eliminates several possible deadlocks.
1482 if (!afs_InReadDir(adp)) {
1483 while ((adp->f.states & CStatd)
1484 && (tdc->dflags & DFFetching)
1485 && hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
1486 ReleaseReadLock(&tdc->lock);
1487 ReleaseReadLock(&adp->lock);
1488 afs_osi_Sleep(&tdc->validPos);
1489 ObtainReadLock(&adp->lock);
1490 ObtainReadLock(&tdc->lock);
1492 if (!(adp->f.states & CStatd)
1493 || !hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
1494 ReleaseReadLock(&tdc->lock);
1495 ReleaseReadLock(&adp->lock);
1497 if (tname && tname != aname)
1498 osi_FreeLargeSpace(tname);
1503 /* Save the version number for when we call osi_dnlc_enter */
1504 hset(versionNo, tdc->f.versionNo);
1507 * check for, and handle "@sys" if it's there. We should be able
1508 * to avoid the alloc and the strcpy with a little work, but it's
1509 * not pressing. If there aren't any remote users (ie, via the
1510 * NFS translator), we have a slightly easier job.
1511 * the faster way to do this is to check for *aname == '@' and if
1512 * it's there, check for @sys, otherwise, assume there's no @sys
1513 * then, if the lookup fails, check for .*@sys...
1515 /* above now implemented by Check_AtSys and Next_AtSys */
1517 /* lookup the name in the appropriate dir, and return a cache entry
1518 * on the resulting fid */
1520 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1523 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1524 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
1526 afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
1528 tname = sysState.name;
1530 ReleaseReadLock(&tdc->lock);
1531 if (!afs_InReadDir(adp))
1534 if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1535 ReleaseReadLock(&adp->lock);
1537 if (tname[0] == '.')
1538 afs_LookupAFSDB(tname + 1);
1540 afs_LookupAFSDB(tname);
1541 if (tname && tname != aname)
1542 osi_FreeLargeSpace(tname);
1545 ReleaseReadLock(&adp->lock);
1548 /* new fid has same cell and volume */
1549 tfid.Cell = adp->f.fid.Cell;
1550 tfid.Fid.Volume = adp->f.fid.Fid.Volume;
1551 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1552 ICL_TYPE_STRING, tname, ICL_TYPE_FID, &tfid,
1553 ICL_TYPE_INT32, code);
1556 if (code != ENOENT) {
1557 printf("LOOKUP dirLookupOff -> %d\n", code);
1562 /* prefetch some entries, if the dir is currently open. The variable
1563 * dirCookie tells us where to start prefetching from.
1565 if (!AFS_IS_DISCONNECTED &&
1566 AFSDOBULK && adp->opens > 0 && !(adp->f.states & CForeign)
1567 && !afs_IsDynroot(adp) && !afs_InReadDir(adp)) {
1569 /* if the entry is not in the cache, or is in the cache,
1570 * but hasn't been statd, then do a bulk stat operation.
1574 ObtainReadLock(&afs_xvcache);
1575 tvc = afs_FindVCache(&tfid, &retry, 0 /* !stats,!lru */ );
1576 ReleaseReadLock(&afs_xvcache);
1577 } while (tvc && retry);
1579 if (!tvc || !(tvc->f.states & CStatd))
1580 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1584 /* if the vcache isn't usable, release it */
1585 if (tvc && !(tvc->f.states & CStatd)) {
1586 #ifndef AFS_FBSD80_ENV
1596 /* now get the status info, if we don't already have it */
1597 /* This is kind of weird, but we might wind up accidentally calling
1598 * RXAFS_Lookup because we happened upon a file which legitimately
1599 * has a 0 uniquifier. That is the result of allowing unique to wrap
1600 * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1601 * the file has not yet been looked up.
1604 afs_int32 cached = 0;
1605 if (!tfid.Fid.Unique && (adp->f.states & CForeign)) {
1606 tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
1608 if (!tvc && !bulkcode) { /* lookup failed or wasn't called */
1609 tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
1612 } /* sub-block just to reduce stack usage */
1615 if (adp->f.states & CForeign)
1616 tvc->f.states |= CForeign;
1617 tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
1618 tvc->f.parent.unique = adp->f.fid.Fid.Unique;
1619 tvc->f.states &= ~CBulkStat;
1621 if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
1622 ObtainSharedLock(&tvc->lock, 680);
1623 if (!tvc->linkData) {
1624 UpgradeSToWLock(&tvc->lock, 681);
1625 code = afs_HandleLink(tvc, &treq);
1626 ConvertWToRLock(&tvc->lock);
1628 ConvertSToRLock(&tvc->lock);
1631 if (!code && !afs_strchr(tvc->linkData, ':'))
1633 ReleaseReadLock(&tvc->lock);
1635 if (tvc->mvstat == 1 && (tvc->f.states & CMValid) && tvc->mvid != NULL)
1636 force_eval = 1; /* This is now almost for free, get it correct */
1638 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1639 if (!(flags & AFS_LOOKUP_NOEVAL))
1640 /* don't eval mount points */
1641 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1642 if (tvc->mvstat == 1 && force_eval) {
1643 /* a mt point, possibly unevaluated */
1644 struct volume *tvolp;
1646 ObtainWriteLock(&tvc->lock, 133);
1647 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1648 ReleaseWriteLock(&tvc->lock);
1651 #ifndef AFS_FBSD80_ENV
1655 afs_PutVolume(tvolp, WRITE_LOCK);
1659 /* next, we want to continue using the target of the mt point */
1660 if (tvc->mvid && (tvc->f.states & CMValid)) {
1662 /* now lookup target, to set .. pointer */
1663 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1664 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID,
1666 uvc = tvc; /* remember for later */
1668 if (tvolp && (tvolp->states & VForeign)) {
1669 /* XXXX tvolp has ref cnt on but not locked! XXX */
1671 afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
1673 tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
1675 #ifndef AFS_FBSD80_ENV
1676 afs_PutVCache(uvc); /* we're done with it */
1682 afs_PutVolume(tvolp, WRITE_LOCK);
1687 /* now, if we came via a new mt pt (say because of a new
1688 * release of a R/O volume), we must reevaluate the ..
1689 * ptr to point back to the appropriate place */
1691 ObtainWriteLock(&tvc->lock, 134);
1692 if (tvc->mvid == NULL) {
1693 tvc->mvid = (struct VenusFid *)
1694 osi_AllocSmallSpace(sizeof(struct VenusFid));
1696 /* setup backpointer */
1697 *tvc->mvid = tvolp->dotdot;
1698 ReleaseWriteLock(&tvc->lock);
1699 afs_PutVolume(tvolp, WRITE_LOCK);
1702 #ifndef AFS_FBSD80_ENV
1707 afs_PutVolume(tvolp, WRITE_LOCK);
1712 if (tvc && !VREFCOUNT_GT(tvc, 0)) {
1717 /* if we get here, we found something in a directory that couldn't
1718 * be located (a Multics "connection failure"). If the volume is
1719 * read-only, we try flushing this entry from the cache and trying
1721 if (!AFS_IS_DISCONNECTED) {
1724 tv = afs_GetVolume(&adp->f.fid, &treq, READ_LOCK);
1726 if (tv->states & VRO) {
1727 pass = 1; /* try this *once* */
1728 ObtainWriteLock(&afs_xcbhash, 495);
1729 afs_DequeueCallback(adp);
1730 /* re-stat to get later version */
1731 adp->f.states &= ~CStatd;
1732 ReleaseWriteLock(&afs_xcbhash);
1733 osi_dnlc_purgedp(adp);
1734 afs_PutVolume(tv, READ_LOCK);
1737 afs_PutVolume(tv, READ_LOCK);
1742 printf("Network down in afs_lookup\n");
1748 /* put the network buffer back, if need be */
1749 if (tname != aname && tname)
1750 osi_FreeLargeSpace(tname);
1753 /* Handle RENAME; only need to check rename "." */
1754 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1755 if (!FidCmp(&(tvc->f.fid), &(adp->f.fid))) {
1756 afs_PutVCache(*avcp);
1758 afs_PutFakeStat(&fakestate);
1759 return afs_CheckCode(EISDIR, &treq, 18);
1762 #endif /* AFS_OSF_ENV */
1765 afs_AddMarinerName(aname, tvc);
1767 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1768 if (!(flags & AFS_LOOKUP_NOEVAL)) {
1769 /* Here we don't enter the name into the DNLC because we want the
1770 * evaluated mount dir to be there (the vcache for the mounted
1771 * volume) rather than the vc of the mount point itself. We can
1772 * still find the mount point's vc in the vcache by its fid. */
1773 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1774 if (!hit && force_eval) {
1775 osi_dnlc_enter(adp, aname, tvc, &versionNo);
1777 #ifdef AFS_LINUX20_ENV
1778 /* So Linux inode cache is up to date. */
1779 code = afs_VerifyVCache(tvc, &treq);
1781 afs_PutFakeStat(&fakestate);
1782 AFS_DISCON_UNLOCK();
1783 return 0; /* can't have been any errors if hit and !code */
1786 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1793 code = afs_CheckCode(code, &treq, 19);
1795 /* If there is an error, make sure *avcp is null.
1796 * Alphas panic otherwise - defect 10719.
1801 afs_PutFakeStat(&fakestate);
1802 AFS_DISCON_UNLOCK();