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
18 * AFS_EQ_ATSYS (macro)
22 #include <afsconfig.h>
23 #include "../afs/param.h"
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/exporter.h"
33 #include "../afs/afs_osidnlc.h"
37 * A few definitions. This is until we have a proper header file
38 * which has prototypes for all functions
41 extern struct DirEntry * afs_dir_GetBlob();
43 extern afs_rwlock_t afs_xvcache;
44 extern afs_rwlock_t afs_xcbhash;
45 extern struct afs_exporter *afs_nfsexporter;
46 extern char *afs_sysname;
47 extern char *afs_sysnamelist[];
48 extern int afs_sysnamecount;
49 extern struct afs_q VLRU; /*vcache LRU*/
50 #ifdef AFS_LINUX22_ENV
51 extern struct inode_operations afs_symlink_iops, afs_dir_iops;
55 afs_int32 afs_bulkStatsDone;
56 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
57 int afs_fakestat_enable = 0; /* 1: fakestat-all, 2: fakestat-crosscell */
60 /* this would be faster if it did comparison as int32word, but would be
61 * dependant on byte-order and alignment, and I haven't figured out
62 * what "@sys" is in binary... */
63 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
65 char *afs_strcat(register char *s1, register char *s2)
74 while ((*s1++ = *s2++))
80 char *afs_index(register char *a, register char c)
83 AFS_STATCNT(afs_index);
85 if (tc == c) return a;
91 /* call under write lock, evaluate mvid field from a mt pt.
92 * avc is the vnode of the mount point object; must be write-locked.
93 * advc is the vnode of the containing directory (optional; if NULL and
94 * EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
95 * avolpp is where we return a pointer to the volume named by the mount pt, if success
96 * areq is the identity of the caller.
98 * NOTE: this function returns a held volume structure in *volpp if it returns 0!
100 int EvalMountPoint(register struct vcache *avc, struct vcache *advc,
101 struct volume **avolpp, register struct vrequest *areq)
104 struct volume *tvp = 0;
105 struct VenusFid tfid;
107 char *cpos, *volnamep;
109 afs_int32 prefetchRO; /* 1=>No 2=>Yes */
110 afs_int32 mtptCell, assocCell, hac=0;
111 afs_int32 samecell, roname, len;
113 AFS_STATCNT(EvalMountPoint);
115 if (avc->mvid && (avc->states & CMValid)) return 0; /* done while racing */
118 code = afs_HandleLink(avc, areq);
119 if (code) return code;
121 /* Determine which cell and volume the mointpoint goes to */
122 type = avc->linkData[0]; /* '#'=>Regular '%'=>RW */
123 cpos = afs_index(&avc->linkData[1], ':'); /* if cell name present */
127 tcell = afs_GetCellByName(&avc->linkData[1], READ_LOCK);
130 volnamep = &avc->linkData[1];
131 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
133 if (!tcell) return ENODEV;
135 mtptCell = tcell->cellNum; /* The cell for the mountpoint */
137 hac = 1; /* has associated cell */
138 assocCell = tcell->lcellp->cellNum; /* The associated cell */
140 afs_PutCell(tcell, READ_LOCK);
142 /* Is volume name a "<n>.backup" or "<n>.readonly" name */
143 len = strlen(volnamep);
144 roname = ((len > 9) && (strcmp(&volnamep[len - 9],".readonly") == 0)) ||
145 ((len > 7) && (strcmp(&volnamep[len - 7],".backup") == 0));
147 /* When we cross mountpoint, do we stay in the same cell */
148 samecell = (avc->fid.Cell == mtptCell) || (hac && (avc->fid.Cell == assocCell));
150 /* Decide whether to prefetch the RO. Also means we want the RO.
151 * If this is a regular mountpoint with a RW volume name and
152 * we cross a cell boundary -or- start from a RO volume, then we will
153 * want to prefetch the RO volume when we get the RW below.
155 if ( (type == '#') && !roname && (!samecell || (avc->states & CRO)) ) {
156 prefetchRO = 2; /* Yes, prefetch the RO */
158 prefetchRO = 1; /* No prefetch of the RO */
161 /* Get the volume struct. Unless this volume name has ".readonly" or
162 * ".backup" in it, this will get the volume struct for the RW volume.
163 * The RO volume will be prefetched if requested (but not returned).
165 tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetchRO, areq, WRITE_LOCK);
167 /* If no volume was found in this cell, try the associated linked cell */
168 if (!tvp && hac && areq->volumeError) {
169 tvp = afs_GetVolumeByName(volnamep, assocCell, prefetchRO, areq, WRITE_LOCK);
172 /* Still not found. If we are looking for the RO, then perhaps the RW
173 * doesn't exist? Try adding ".readonly" to volname and look for that.
174 * Don't know why we do this. Would have still found it in above call - jpm.
176 if (!tvp && (prefetchRO == 2)) {
177 buf = (char *)osi_AllocSmallSpace(strlen(volnamep)+10);
179 strcpy(buf, volnamep);
180 afs_strcat(buf, ".readonly");
182 tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
184 /* Try the associated linked cell if failed */
185 if (!tvp && hac && areq->volumeError) {
186 tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
188 osi_FreeSmallSpace(buf);
191 if (!tvp) return ENODEV; /* Couldn't find the volume */
193 /* Don't cross mountpoint from a BK to a BK volume */
194 if ((avc->states & CBackup) && (tvp->states & VBackup)) {
195 afs_PutVolume(tvp, WRITE_LOCK);
199 /* If we want (prefetched) the RO and it exists, then drop the
200 * RW volume and get the RO. Othewise, go with the RW.
202 if ((prefetchRO == 2) && tvp->roVol) {
203 tfid.Fid.Volume = tvp->roVol; /* remember RO volume */
204 tfid.Cell = tvp->cell;
205 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
206 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
207 if (!tvp) return ENODEV; /* oops, can't do it */
211 avc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
212 avc->mvid->Cell = tvp->cell;
213 avc->mvid->Fid.Volume = tvp->volume;
214 avc->mvid->Fid.Vnode = 1;
215 avc->mvid->Fid.Unique = 1;
216 avc->states |= CMValid;
218 /* Used to: if the mount point is stored within a backup volume,
219 * then we should only update the parent pointer information if
220 * there's none already set, so as to avoid updating a volume's ..
221 * info with something in an OldFiles directory.
223 * Next two lines used to be under this if:
225 * if (!(avc->states & CBackup) || tvp->dotdot.Fid.Volume == 0)
227 * Now: update mount point back pointer on every call, so that we handle
228 * multiple mount points better. This way, when du tries to go back
229 * via chddir(".."), it will end up exactly where it started, yet
230 * cd'ing via a new path to a volume will reset the ".." pointer
233 tvp->mtpoint = avc->fid; /* setup back pointer to mtpoint */
234 if (advc) tvp->dotdot = advc->fid;
243 * Must be called on an afs_fakestat_state object before calling
244 * afs_EvalFakeStat or afs_PutFakeStat. Calling afs_PutFakeStat
245 * without calling afs_EvalFakeStat is legal, as long as this
246 * function is called.
248 void afs_InitFakeStat(struct afs_fakestat_state *state)
250 if (!afs_fakestat_enable)
255 state->need_release = 0;
259 * afs_EvalFakeStat_int
261 * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
262 * which is called by those wrapper functions.
264 * Only issues RPCs if canblock is non-zero.
266 int afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
267 struct vrequest *areq, int canblock)
269 struct vcache *tvc, *root_vp;
270 struct volume *tvolp = NULL;
273 if (!afs_fakestat_enable)
276 osi_Assert(state->valid == 1);
277 osi_Assert(state->did_eval == 0);
281 if (tvc->mvstat != 1)
284 /* Is the call to VerifyVCache really necessary? */
285 code = afs_VerifyVCache(tvc, areq);
289 ObtainWriteLock(&tvc->lock, 599);
290 code = EvalMountPoint(tvc, NULL, &tvolp, areq);
291 ReleaseWriteLock(&tvc->lock);
295 tvolp->dotdot = tvc->fid;
296 tvolp->dotdot.Fid.Vnode = tvc->parentVnode;
297 tvolp->dotdot.Fid.Unique = tvc->parentUnique;
300 if (tvc->mvid && (tvc->states & CMValid)) {
306 ObtainWriteLock(&afs_xvcache, 597);
307 root_vp = afs_FindVCache(tvc->mvid, &retry, 0);
308 if (root_vp && retry) {
309 ReleaseWriteLock(&afs_xvcache);
310 afs_PutVCache(root_vp);
312 } while (root_vp && retry);
313 ReleaseWriteLock(&afs_xvcache);
315 root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
318 code = canblock ? ENOENT : 0;
322 /* Is this always kosher? Perhaps we should instead use
323 * NBObtainWriteLock to avoid potential deadlock.
325 ObtainWriteLock(&root_vp->lock, 598);
327 root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
328 *root_vp->mvid = tvolp->dotdot;
329 ReleaseWriteLock(&root_vp->lock);
331 state->need_release = 1;
332 state->root_vp = root_vp;
336 code = canblock ? ENOENT : 0;
341 afs_PutVolume(tvolp, WRITE_LOCK);
348 * Automatically does the equivalent of EvalMountPoint for vcache entries
349 * which are mount points. Remembers enough state to properly release
350 * the volume root vcache when afs_PutFakeStat() is called.
352 * State variable must be initialized by afs_InitFakeState() beforehand.
354 * Returns 0 when everything succeeds and *avcp points to the vcache entry
355 * that should be used for the real vnode operation. Returns non-zero if
356 * something goes wrong and the error code should be returned to the user.
359 afs_EvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
360 struct vrequest *areq)
362 return afs_EvalFakeStat_int(avcp, state, areq, 1);
366 * afs_TryEvalFakeStat
368 * Same as afs_EvalFakeStat, but tries not to talk to remote servers
369 * and only evaluate the mount point if all the data is already in
372 * Returns 0 if everything succeeds and *avcp points to a valid
373 * vcache entry (possibly evaluated).
375 int afs_TryEvalFakeStat(struct vcache **avcp, struct afs_fakestat_state *state,
376 struct vrequest *areq)
378 return afs_EvalFakeStat_int(avcp, state, areq, 0);
384 * Perform any necessary cleanup at the end of a vnode op, given that
385 * afs_InitFakeStat was previously called with this state.
387 void afs_PutFakeStat(struct afs_fakestat_state *state)
389 if (!afs_fakestat_enable)
392 osi_Assert(state->valid == 1);
393 if (state->need_release)
394 afs_PutVCache(state->root_vp);
398 int afs_ENameOK(register char *aname)
403 AFS_STATCNT(ENameOK);
404 tlen = strlen(aname);
405 if (tlen >= 4 && strcmp(aname+tlen-4, "@sys") == 0) return 0;
409 int afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
412 static char sysname[MAXSYSNAME];
413 register struct unixuser *au;
414 register afs_int32 error;
416 if (!afs_nfsexporter) {
417 strcpy(bufp, afs_sysname);
420 AFS_STATCNT(getsysname);
421 au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
424 error = EXP_SYSNAME(au->exporter, NULL, bufp);
426 strcpy(bufp, "@sys");
429 strcpy(bufp, afs_sysname);
434 int Check_AtSys(register struct vcache *avc, const char *aname,
435 struct sysname_info *state, struct vrequest *areq)
437 if (AFS_EQ_ATSYS(aname)) {
439 state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
441 state->index = afs_getsysname(areq, avc, state->name);
450 int Next_AtSys(register struct vcache *avc, struct vrequest *areq,
451 struct sysname_info *state)
453 if (state->index == -1)
454 return 0; /* No list */
456 /* Check for the initial state of aname != "@sys" in Check_AtSys*/
457 if (state->offset == -1 && state->allocked == 0) {
458 register char *tname;
459 /* Check for .*@sys */
460 for (tname=state->name; *tname; tname++)
461 /*Move to the end of the string*/;
462 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
463 state->offset = (tname - 4) - state->name;
464 tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
465 strncpy(tname, state->name, state->offset);
468 state->index = afs_getsysname(areq, avc, state->name+state->offset);
471 return 0; /* .*@sys doesn't match either */
472 } else if (++(state->index) >= afs_sysnamecount
473 || !afs_sysnamelist[state->index])
474 return 0; /* end of list */
475 strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
479 #if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
480 extern int BlobScan(ino64_t *afile, afs_int32 ablob);
482 #if defined AFS_LINUX_64BIT_KERNEL
483 extern int BlobScan(long *afile, afs_int32 ablob);
485 extern int BlobScan(afs_int32 *afile, afs_int32 ablob);
490 /* called with an unlocked directory and directory cookie. Areqp
491 * describes who is making the call.
492 * Scans the next N (about 30, typically) directory entries, and does
493 * a bulk stat call to stat them all.
495 * Must be very careful when merging in RPC responses, since we dont
496 * want to overwrite newer info that was added by a file system mutating
497 * call that ran concurrently with our bulk stat call.
499 * We do that, as described below, by not merging in our info (always
500 * safe to skip the merge) if the status info is valid in the vcache entry.
502 * If adapt ever implements the bulk stat RPC, then this code will need to
503 * ensure that vcaches created for failed RPC's to older servers have the
506 static struct vcache *BStvc = NULL;
508 int afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
510 int nentries; /* # of entries to prefetch */
511 int nskip; /* # of slots in the LRU queue to skip */
512 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
513 struct dcache *dcp; /* chunk containing the dir block */
514 char *statMemp; /* status memory block */
515 char *cbfMemp; /* callback and fid memory block */
516 afs_size_t temp; /* temp for holding chunk length, &c. */
517 struct AFSFid *fidsp; /* file IDs were collecting */
518 struct AFSCallBack *cbsp; /* call back pointers */
519 struct AFSCallBack *tcbp; /* temp callback ptr */
520 struct AFSFetchStatus *statsp; /* file status info */
521 struct AFSVolSync volSync; /* vol sync return info */
522 struct vcache *tvcp; /* temp vcp */
523 struct afs_q *tq; /* temp queue variable */
524 AFSCBFids fidParm; /* file ID parm for bulk stat */
525 AFSBulkStats statParm; /* stat info parm for bulk stat */
526 int fidIndex; /* which file were stating */
527 struct conn *tcp; /* conn for call */
528 AFSCBs cbParm; /* callback parm for bulk stat */
529 struct server *hostp = 0; /* host we got callback from */
530 long origEvenCBs; /* original # of callbacks for even-fid files */
531 long origOddCBs; /* original # of callbacks for odd-fid files */
532 long origEvenZaps; /* original # of recycles for even-fid files */
533 long origOddZaps; /* original # of recycles for odd-fid files */
534 long startTime; /* time we started the call,
535 * for callback expiration base
537 afs_size_t statSeqNo; /* Valued of file size to detect races */
538 int code; /* error code */
539 long newIndex; /* new index in the dir */
540 struct DirEntry *dirEntryp; /* dir entry we are examining */
542 struct VenusFid afid; /* file ID we are using now */
543 struct VenusFid tfid; /* another temp. file ID */
544 afs_int32 retry; /* handle low-level SGI MP race conditions */
545 long volStates; /* flags from vol structure */
546 struct volume *volp=0; /* volume ptr */
547 struct VenusFid dotdot;
548 int flagIndex; /* First file with bulk fetch flag set */
549 int inlinebulk=0; /* Did we use InlineBulk RPC or not? */
552 /* first compute some basic parameters. We dont want to prefetch more
553 * than a fraction of the cache in any given call, and we want to preserve
554 * a portion of the LRU queue in any event, so as to avoid thrashing
555 * the entire stat cache (we will at least leave some of it alone).
556 * presently dont stat more than 1/8 the cache in any one call. */
557 nentries = afs_cacheStats / 8;
559 /* dont bother prefetching more than one calls worth of info */
560 if (nentries > AFSCBMAX) nentries = AFSCBMAX;
562 /* heuristic to make sure that things fit in 4K. This means that
563 * we shouldnt make it any bigger than 47 entries. I am typically
564 * going to keep it a little lower, since we don't want to load
565 * too much of the stat cache.
567 if (nentries > 30) nentries = 30;
569 /* now, to reduce the stack size, well allocate two 4K blocks,
570 * one for fids and callbacks, and one for stat info. Well set
571 * up our pointers to the memory from there, too.
573 statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
574 statsp = (struct AFSFetchStatus *) statMemp;
575 cbfMemp = osi_AllocLargeSpace(nentries *
576 (sizeof(AFSCallBack) + sizeof(AFSFid)));
577 fidsp = (AFSFid *) cbfMemp;
578 cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
580 /* next, we must iterate over the directory, starting from the specified
581 * cookie offset (dirCookie), and counting out nentries file entries.
582 * We skip files that already have stat cache entries, since we
583 * dont want to bulk stat files that are already in the cache.
586 code = afs_VerifyVCache(adp, areqp);
589 dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
595 /* lock the directory cache entry */
596 ObtainReadLock(&adp->lock);
597 ObtainReadLock(&dcp->lock);
600 * Make sure that the data in the cache is current. There are two
601 * cases we need to worry about:
602 * 1. The cache data is being fetched by another process.
603 * 2. The cache data is no longer valid
605 while ((adp->states & CStatd)
606 && (dcp->dflags & DFFetching)
607 && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
608 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
609 ICL_TYPE_STRING, __FILE__,
610 ICL_TYPE_INT32, __LINE__,
611 ICL_TYPE_POINTER, dcp,
612 ICL_TYPE_INT32, dcp->dflags);
613 ReleaseReadLock(&dcp->lock);
614 ReleaseReadLock(&adp->lock);
615 afs_osi_Sleep(&dcp->validPos);
616 ObtainReadLock(&adp->lock);
617 ObtainReadLock(&dcp->lock);
619 if (!(adp->states & CStatd)
620 || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
621 ReleaseReadLock(&dcp->lock);
622 ReleaseReadLock(&adp->lock);
627 /* Generate a sequence number so we can tell whether we should
628 * store the attributes when processing the response. This number is
629 * stored in the file size when we set the CBulkFetching bit. If the
630 * CBulkFetching is still set and this value hasn't changed, then
631 * we know we were the last to set CBulkFetching bit for this file,
632 * and it is safe to set the status information for this file.
634 statSeqNo = bulkStatCounter++;
636 /* now we have dir data in the cache, so scan the dir page */
639 while (1) { /* Should probably have some constant bound */
640 /* look for first safe entry to examine in the directory. BlobScan
641 * looks for a the 1st allocated dir after the dirCookie slot.
643 newIndex = BlobScan(&dcp->f.inode, (dirCookie>>5));
644 if (newIndex == 0) break;
646 /* remember the updated directory cookie */
647 dirCookie = newIndex << 5;
649 /* get a ptr to the dir entry */
650 dirEntryp =(struct DirEntry *)afs_dir_GetBlob(&dcp->f.inode, newIndex);
651 if (!dirEntryp) break;
653 /* dont copy more than we have room for */
654 if (fidIndex >= nentries) {
655 DRelease((char *) dirEntryp, 0);
659 /* now, if the dir entry looks good, copy it out to our list. Vnode
660 * 0 means deleted, although it should also be free were it deleted.
662 if (dirEntryp->fid.vnode != 0) {
663 /* dont copy entries we have in our cache. This check will
664 * also make us skip "." and probably "..", unless it has
665 * disappeared from the cache since we did our namei call.
667 tfid.Cell = adp->fid.Cell;
668 tfid.Fid.Volume = adp->fid.Fid.Volume;
669 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
670 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
673 ObtainWriteLock(&afs_xvcache, 130);
674 tvcp = afs_FindVCache(&tfid, &retry, 0 /* no stats | LRU */);
676 ReleaseWriteLock(&afs_xvcache);
679 } while (tvcp && retry);
680 if (!tvcp) { /* otherwise, create manually */
681 tvcp = afs_NewVCache(&tfid, hostp);
682 ObtainWriteLock(&tvcp->lock, 505);
683 ReleaseWriteLock(&afs_xvcache);
684 afs_RemoveVCB(&tfid);
685 ReleaseWriteLock(&tvcp->lock);
687 ReleaseWriteLock(&afs_xvcache);
690 goto done; /* can't happen at present, more's the pity */
692 /* WARNING: afs_DoBulkStat uses the Length field to store a
693 * sequence number for each bulk status request. Under no
694 * circumstances should afs_DoBulkStat store a sequence number
695 * if the new length will be ignored when afs_ProcessFS is
696 * called with new stats. */
698 if (!(tvcp->states & (CStatd|CBulkFetching))
699 && (tvcp->execsOrWriters <= 0)
700 && !afs_DirtyPages(tvcp)
701 && !AFS_VN_MAPPED((vnode_t*)tvcp))
703 if (!(tvcp->states & (CStatd|CBulkFetching))
704 && (tvcp->execsOrWriters <= 0)
705 && !afs_DirtyPages(tvcp))
709 /* this entry doesnt exist in the cache, and is not
710 * already being fetched by someone else, so add it to the
711 * list of file IDs to obtain.
713 * We detect a callback breaking race condition by checking the
714 * CBulkFetching state bit and the value in the file size.
715 * It is safe to set the status only if the CBulkFetching
716 * flag is still set and the value in the file size does
719 * Don't fetch status for dirty files. We need to
720 * preserve the value of the file size. We could
721 * flush the pages, but it wouldn't be worthwhile.
723 memcpy((char *)(fidsp+fidIndex), (char *) &tfid.Fid, sizeof(*fidsp));
724 tvcp->states |= CBulkFetching;
725 tvcp->m.Length = statSeqNo;
729 } /* if dir vnode has non-zero entry */
731 /* move to the next dir entry by adding in the # of entries
732 * used by this dir entry.
734 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
735 DRelease((char *) dirEntryp, 0);
736 if (temp <= 0) break;
738 } /* while loop over all dir entries */
740 /* now release the dir lock and prepare to make the bulk RPC */
741 ReleaseReadLock(&dcp->lock);
742 ReleaseReadLock(&adp->lock);
744 /* release the chunk */
747 /* dont make a null call */
748 if (fidIndex == 0) goto done;
751 /* setup the RPC parm structures */
752 fidParm.AFSCBFids_len = fidIndex;
753 fidParm.AFSCBFids_val = fidsp;
754 statParm.AFSBulkStats_len = fidIndex;
755 statParm.AFSBulkStats_val = statsp;
756 cbParm.AFSCBs_len = fidIndex;
757 cbParm.AFSCBs_val = cbsp;
759 /* start the timer; callback expirations are relative to this */
760 startTime = osi_Time();
762 tcp = afs_Conn(&adp->fid, areqp, SHARED_LOCK);
764 hostp = tcp->srvr->server;
765 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
768 if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
769 code = RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
771 if (code == RXGEN_OPCODE) {
772 tcp->srvr->server->flags |= SNO_INLINEBULK;
774 code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
780 code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
787 } while (afs_Analyze(tcp, code, &adp->fid, areqp,
788 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL));
790 /* now, if we didnt get the info, bail out. */
793 /* we need vol flags to create the entries properly */
794 dotdot.Fid.Volume = 0;
795 volp = afs_GetVolume(&adp->fid, areqp, READ_LOCK);
797 volStates = volp->states;
798 if (volp->dotdot.Fid.Volume != 0)
799 dotdot = volp->dotdot;
803 /* find the place to merge the info into We do this by skipping
804 * nskip entries in the LRU queue. The more we skip, the more
805 * we preserve, since the head of the VLRU queue is the most recently
809 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
810 ObtainReadLock(&afs_xvcache);
812 /* actually a serious error, probably should panic. Probably will
813 * panic soon, oh well. */
814 ReleaseReadLock(&afs_xvcache);
815 afs_warnuser("afs_DoBulkStat: VLRU empty!");
818 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
819 refpanic ("Bulkstat VLRU inconsistent");
821 for(tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
822 if (--nskip <= 0) break;
823 else if (QNext(QPrev(tq)) != tq) {
825 refpanic ("BulkStat VLRU inconsistent");
828 if (tq != &VLRU) lruvcp = QTOV(tq);
829 else lruvcp = QTOV(VLRU.next);
831 /* now we have to hold this entry, so that it does not get moved
832 * into the free list while we're running. It could still get
833 * moved within the lru queue, but hopefully that will be rare; it
834 * doesn't hurt nearly as much.
837 osi_vnhold(lruvcp, &retry);
838 ReleaseReadLock(&afs_xvcache); /* could be read lock */
842 /* otherwise, merge in the info. We have to be quite careful here,
843 * since we need to ensure that we don't merge old info over newer
844 * stuff in a stat cache entry. We're very conservative here: we don't
845 * do the merge at all unless we ourselves create the stat cache
846 * entry. That's pretty safe, and should work pretty well, since we
847 * typically expect to do the stat cache creation ourselves.
849 * We also have to take into account racing token revocations.
851 for(i=0; i<fidIndex; i++) {
852 if ((&statsp[i])->errorCode)
854 afid.Cell = adp->fid.Cell;
855 afid.Fid.Volume = adp->fid.Fid.Volume;
856 afid.Fid.Vnode = fidsp[i].Vnode;
857 afid.Fid.Unique = fidsp[i].Unique;
860 ObtainReadLock(&afs_xvcache);
861 tvcp = afs_FindVCache(&afid, &retry, 0/* !stats&!lru*/);
862 ReleaseReadLock(&afs_xvcache);
863 } while (tvcp && retry);
865 /* The entry may no longer exist */
870 /* now we have the entry held, but we need to fill it in */
871 ObtainWriteLock(&tvcp->lock,131);
873 /* if CBulkFetching is not set, or if the file size no longer
874 * matches the value we placed there when we set the CBulkFetching
875 * flag, then someone else has done something with this node,
876 * and we may not have the latest status information for this
877 * file. Leave the entry alone.
879 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
881 ReleaseWriteLock(&tvcp->lock);
886 /* now copy ".." entry back out of volume structure, if necessary */
887 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
889 tvcp->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
890 *tvcp->mvid = dotdot;
893 ObtainWriteLock(&afs_xvcache,132);
894 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
895 refpanic ("Bulkstat VLRU inconsistent2");
897 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
898 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
899 { refpanic ("Bulkstat VLRU inconsistent4"); }
900 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
901 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
902 { refpanic ("Bulkstat VLRU inconsistent5"); }
904 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
905 QRemove(&tvcp->vlruq);
906 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
909 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
910 refpanic ("Bulkstat VLRU inconsistent3");
912 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
913 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
914 { refpanic ("Bulkstat VLRU inconsistent5"); }
915 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
916 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
917 { refpanic ("Bulkstat VLRU inconsistent6"); }
918 ReleaseWriteLock(&afs_xvcache);
920 ObtainWriteLock(&afs_xcbhash, 494);
922 /* We need to check the flags again. We may have missed
923 * something while we were waiting for a lock.
925 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
927 ReleaseWriteLock(&tvcp->lock);
928 ReleaseWriteLock(&afs_xcbhash);
933 /* now merge in the resulting status back into the vnode.
934 * We only do this if the entry looks clear.
936 afs_ProcessFS(tvcp, &statsp[i], areqp);
937 #ifdef AFS_LINUX22_ENV
938 /* overwrite the ops if it's a directory or symlink. */
939 if (vType(tvcp) == VDIR)
940 tvcp->v.v_op = &afs_dir_iops;
941 else if (vType(tvcp) == VLNK)
942 tvcp->v.v_op = &afs_symlink_iops;
945 /* do some accounting for bulk stats: mark this entry as
946 * loaded, so we can tell if we use it before it gets
949 tvcp->states |= CBulkStat;
950 tvcp->states &= ~CBulkFetching;
954 /* merge in vol info */
955 if (volStates & VRO) tvcp->states |= CRO;
956 if (volStates & VBackup) tvcp->states |= CBackup;
957 if (volStates & VForeign) tvcp->states |= CForeign;
959 /* merge in the callback info */
960 tvcp->states |= CTruth;
962 /* get ptr to the callback we are interested in */
965 if (tcbp->ExpirationTime != 0) {
966 tvcp->cbExpires = tcbp->ExpirationTime+startTime;
967 tvcp->callback = hostp;
968 tvcp->states |= CStatd;
969 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
971 else if (tvcp->states & CRO) {
972 /* ordinary callback on a read-only volume -- AFS 3.2 style */
973 tvcp->cbExpires = 3600+startTime;
974 tvcp->callback = hostp;
975 tvcp->states |= CStatd;
976 afs_QueueCallback(tvcp, CBHash(3600), volp);
980 tvcp->states &= ~(CStatd|CUnique);
981 afs_DequeueCallback(tvcp);
982 if ((tvcp->states & CForeign) || (vType(tvcp) == VDIR))
983 osi_dnlc_purgedp (tvcp); /* if it (could be) a directory */
985 ReleaseWriteLock(&afs_xcbhash);
987 ReleaseWriteLock(&tvcp->lock);
988 /* finally, we're done with the entry */
990 } /* for all files we got back */
992 /* finally return the pointer into the LRU queue */
993 afs_PutVCache(lruvcp);
996 /* Be sure to turn off the CBulkFetching flags */
997 for(i=flagIndex; i<fidIndex; i++) {
998 afid.Cell = adp->fid.Cell;
999 afid.Fid.Volume = adp->fid.Fid.Volume;
1000 afid.Fid.Vnode = fidsp[i].Vnode;
1001 afid.Fid.Unique = fidsp[i].Unique;
1004 ObtainReadLock(&afs_xvcache);
1005 tvcp = afs_FindVCache(&afid, &retry, 0/* !stats&!lru*/);
1006 ReleaseReadLock(&afs_xvcache);
1007 } while (tvcp && retry);
1009 && (tvcp->states & CBulkFetching)
1010 && (tvcp->m.Length == statSeqNo)) {
1011 tvcp->states &= ~CBulkFetching;
1014 afs_PutVCache(tvcp);
1018 afs_PutVolume(volp, READ_LOCK);
1020 /* If we did the InlineBulk RPC pull out the return code */
1022 if ((&statsp[0])->errorCode) {
1023 afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->fid, areqp,
1024 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK,
1026 code = (&statsp[0])->errorCode;
1031 osi_FreeLargeSpace(statMemp);
1032 osi_FreeLargeSpace(cbfMemp);
1036 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
1037 static int AFSDOBULK = 1;
1040 afs_lookup(adp, ndp)
1042 struct nameidata *ndp; {
1043 char aname[MAXNAMLEN+1]; /* XXX */
1044 struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
1045 struct ucred *acred = ndp->ni_cred;
1046 int wantparent = ndp->ni_nameiop & WANTPARENT;
1047 int opflag = ndp->ni_nameiop & OPFLAG;
1048 #else /* AFS_OSF_ENV */
1049 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
1050 afs_lookup(OSI_VC_ARG(adp), aname, avcp, pnp, flags, rdir, acred)
1051 struct pathname *pnp;
1055 #if defined(UKERNEL)
1056 afs_lookup(adp, aname, avcp, acred, flags)
1059 afs_lookup(adp, aname, avcp, acred)
1060 #endif /* UKERNEL */
1061 #endif /* SUN5 || SGI */
1063 struct vcache **avcp;
1065 struct AFS_UCRED *acred; {
1067 struct vrequest treq;
1069 register struct vcache *tvc=0;
1070 register afs_int32 code;
1071 register afs_int32 bulkcode = 0;
1072 int pass = 0, hit = 0;
1074 extern afs_int32 afs_mariner; /*Writing activity to log?*/
1076 afs_hyper_t versionNo;
1077 int no_read_access = 0;
1078 struct sysname_info sysState; /* used only for @sys checking */
1079 int dynrootRetry = 1;
1080 struct afs_fakestat_state fakestate;
1081 int tryEvalOnly = 0;
1083 AFS_STATCNT(afs_lookup);
1084 afs_InitFakeStat(&fakestate);
1086 if ((code = afs_InitReq(&treq, acred)))
1090 ndp->ni_dvp = AFSTOV(adp);
1091 memcpy(aname, ndp->ni_ptr, ndp->ni_namelen);
1092 aname[ndp->ni_namelen] = '\0';
1093 #endif /* AFS_OSF_ENV */
1095 #if defined(AFS_DARWIN_ENV)
1096 /* Workaround for MacOSX Finder, which tries to look for
1097 * .DS_Store and Contents under every directory.
1099 if (afs_fakestat_enable && adp->mvstat == 1) {
1100 if (strcmp(aname, ".DS_Store") == 0)
1102 if (strcmp(aname, "Contents") == 0)
1108 code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
1110 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
1111 if (tryEvalOnly && adp->mvstat == 1)
1116 *avcp = NULL; /* Since some callers don't initialize it */
1118 /* come back to here if we encounter a non-existent object in a read-only
1119 volume's directory */
1122 *avcp = NULL; /* Since some callers don't initialize it */
1125 if (!(adp->states & CStatd)) {
1126 if ((code = afs_VerifyVCache2(adp, &treq))) {
1132 /* watch for ".." in a volume root */
1133 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
1134 /* looking up ".." in root via special hacks */
1135 if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
1137 extern struct vcache *afs_globalVp;
1138 if (adp == afs_globalVp) {
1139 struct vnode *rvp = AFSTOV(adp);
1141 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
1142 ndp->ni_dvp = ndp->ni_vp;
1152 /* otherwise we have the fid here, so we use it */
1153 tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
1154 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT,
1155 ICL_TYPE_FID, adp->mvid, ICL_TYPE_POINTER, tvc,
1156 ICL_TYPE_INT32, code);
1158 code = (tvc ? 0 : ENOENT);
1160 if (tvc && !VREFCOUNT(tvc)) {
1164 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code);*/
1169 /* now check the access */
1170 if (treq.uid != adp->last_looker) {
1171 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1176 else adp->last_looker = treq.uid;
1179 /* Check for read access as well. We need read access in order to
1180 stat files, but not to stat subdirectories. */
1181 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
1184 /* special case lookup of ".". Can we check for it sooner in this code,
1185 * for instance, way up before "redo:" ??
1186 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
1187 * invent a lightweight version of GetVCache.
1189 if (aname[0] == '.' && !aname[1]) { /* special case */
1190 ObtainReadLock(&afs_xvcache);
1192 ReleaseReadLock(&afs_xvcache);
1196 if (adp && !VREFCOUNT(adp)) {
1202 Check_AtSys(adp, aname, &sysState, &treq);
1203 tname = sysState.name;
1205 /* 1st Check_AtSys and lookup by tname is required here, for now,
1206 because the dnlc is *not* told to remove entries for the parent
1207 dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1208 if the cached entry for the parent dir is invalidated for a
1210 Otherwise, we'd be able to do a dnlc lookup on an entry ending
1211 w/@sys and know the dnlc was consistent with reality. */
1212 tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
1213 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1215 if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1216 /* need read access on dir to stat non-directory / non-link */
1222 #ifdef AFS_LINUX22_ENV
1223 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1232 #else /* non - LINUX */
1236 #endif /* linux22 */
1240 register struct dcache *tdc;
1241 afs_size_t dirOffset, dirLen;
1243 struct VenusFid tfid;
1245 /* now we have to lookup the next fid */
1246 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
1248 *avcp = NULL; /* redundant, but harmless */
1253 /* now we will just call dir package with appropriate inode.
1254 Dirs are always fetched in their entirety for now */
1255 ObtainReadLock(&adp->lock);
1256 ObtainReadLock(&tdc->lock);
1259 * Make sure that the data in the cache is current. There are two
1260 * cases we need to worry about:
1261 * 1. The cache data is being fetched by another process.
1262 * 2. The cache data is no longer valid
1264 while ((adp->states & CStatd)
1265 && (tdc->dflags & DFFetching)
1266 && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1267 ReleaseReadLock(&tdc->lock);
1268 ReleaseReadLock(&adp->lock);
1269 afs_osi_Sleep(&tdc->validPos);
1270 ObtainReadLock(&adp->lock);
1271 ObtainReadLock(&tdc->lock);
1273 if (!(adp->states & CStatd)
1274 || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1275 ReleaseReadLock(&tdc->lock);
1276 ReleaseReadLock(&adp->lock);
1281 /* Save the version number for when we call osi_dnlc_enter */
1282 hset(versionNo, tdc->f.versionNo);
1285 * check for, and handle "@sys" if it's there. We should be able
1286 * to avoid the alloc and the strcpy with a little work, but it's
1287 * not pressing. If there aren't any remote users (ie, via the
1288 * NFS translator), we have a slightly easier job.
1289 * the faster way to do this is to check for *aname == '@' and if
1290 * it's there, check for @sys, otherwise, assume there's no @sys
1291 * then, if the lookup fails, check for .*@sys...
1293 /* above now implemented by Check_AtSys and Next_AtSys */
1295 /* lookup the name in the appropriate dir, and return a cache entry
1296 on the resulting fid */
1297 theDir = tdc->f.inode;
1298 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1300 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1301 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
1302 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1304 tname = sysState.name;
1306 ReleaseReadLock(&tdc->lock);
1309 if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1310 ReleaseReadLock(&adp->lock);
1312 if (tname[0] == '.')
1313 afs_LookupAFSDB(tname + 1);
1315 afs_LookupAFSDB(tname);
1316 if (tname && tname != aname) osi_FreeLargeSpace(tname);
1319 ReleaseReadLock(&adp->lock);
1322 /* new fid has same cell and volume */
1323 tfid.Cell = adp->fid.Cell;
1324 tfid.Fid.Volume = adp->fid.Fid.Volume;
1325 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1326 ICL_TYPE_STRING, tname,
1327 ICL_TYPE_FID, &tfid, ICL_TYPE_INT32, code);
1330 if (code != ENOENT) {
1331 printf("LOOKUP dirLookupOff -> %d\n", code);
1336 /* prefetch some entries, if the dir is currently open. The variable
1337 * dirCookie tells us where to start prefetching from.
1339 if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign) && !afs_IsDynroot(adp)) {
1341 /* if the entry is not in the cache, or is in the cache,
1342 * but hasn't been statd, then do a bulk stat operation.
1346 ObtainReadLock(&afs_xvcache);
1347 tvc = afs_FindVCache(&tfid, &retry, 0/* !stats,!lru */);
1348 ReleaseReadLock(&afs_xvcache);
1349 } while (tvc && retry);
1351 if (!tvc || !(tvc->states & CStatd))
1352 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1356 /* if the vcache isn't usable, release it */
1357 if (tvc && !(tvc->states & CStatd)) {
1366 /* now get the status info, if we don't already have it */
1367 /* This is kind of weird, but we might wind up accidentally calling
1368 * RXAFS_Lookup because we happened upon a file which legitimately
1369 * has a 0 uniquifier. That is the result of allowing unique to wrap
1370 * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1371 * the file has not yet been looked up.
1374 afs_int32 cached = 0;
1375 if (!tfid.Fid.Unique && (adp->states & CForeign)) {
1376 tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
1378 if (!tvc && !bulkcode) { /* lookup failed or wasn't called */
1379 tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
1382 } /* sub-block just to reduce stack usage */
1385 int force_eval = afs_fakestat_enable ? 0 : 1;
1387 if (adp->states & CForeign)
1388 tvc->states |= CForeign;
1389 tvc->parentVnode = adp->fid.Fid.Vnode;
1390 tvc->parentUnique = adp->fid.Fid.Unique;
1391 tvc->states &= ~CBulkStat;
1393 if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
1394 ObtainSharedLock(&tvc->lock, 680);
1395 if (!tvc->linkData) {
1396 UpgradeSToWLock(&tvc->lock, 681);
1397 code = afs_HandleLink(tvc, &treq);
1398 ConvertWToRLock(&tvc->lock);
1400 ConvertSToRLock(&tvc->lock);
1403 if (!code && !strchr(tvc->linkData, ':'))
1405 ReleaseReadLock(&tvc->lock);
1408 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1409 if (!(flags & AFS_LOOKUP_NOEVAL))
1410 /* don't eval mount points */
1411 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1412 if (tvc->mvstat == 1 && force_eval) {
1413 /* a mt point, possibly unevaluated */
1414 struct volume *tvolp;
1416 ObtainWriteLock(&tvc->lock,133);
1417 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1418 ReleaseWriteLock(&tvc->lock);
1422 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1426 /* next, we want to continue using the target of the mt point */
1427 if (tvc->mvid && (tvc->states & CMValid)) {
1429 /* now lookup target, to set .. pointer */
1430 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1431 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID, &tvc->fid);
1432 uvc = tvc; /* remember for later */
1434 if (tvolp && (tvolp->states & VForeign)) {
1435 /* XXXX tvolp has ref cnt on but not locked! XXX */
1436 tvc = afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
1438 tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
1440 afs_PutVCache(uvc); /* we're done with it */
1445 afs_PutVolume(tvolp, WRITE_LOCK);
1450 /* now, if we came via a new mt pt (say because of a new
1451 * release of a R/O volume), we must reevaluate the ..
1452 * ptr to point back to the appropriate place */
1454 ObtainWriteLock(&tvc->lock,134);
1455 if (tvc->mvid == NULL) {
1456 tvc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
1458 /* setup backpointer */
1459 *tvc->mvid = tvolp->dotdot;
1460 ReleaseWriteLock(&tvc->lock);
1461 afs_PutVolume(tvolp, WRITE_LOCK);
1467 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1472 if (tvc && !VREFCOUNT(tvc)) {
1478 /* if we get here, we found something in a directory that couldn't
1479 be located (a Multics "connection failure"). If the volume is
1480 read-only, we try flushing this entry from the cache and trying
1484 tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
1486 if (tv->states & VRO) {
1487 pass = 1; /* try this *once* */
1488 ObtainWriteLock(&afs_xcbhash, 495);
1489 afs_DequeueCallback(adp);
1490 /* re-stat to get later version */
1491 adp->states &= ~CStatd;
1492 ReleaseWriteLock(&afs_xcbhash);
1493 osi_dnlc_purgedp(adp);
1494 afs_PutVolume(tv, READ_LOCK);
1497 afs_PutVolume(tv, READ_LOCK);
1504 /* put the network buffer back, if need be */
1505 if (tname != aname && tname) osi_FreeLargeSpace(tname);
1508 /* Handle RENAME; only need to check rename "." */
1509 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1510 if (!FidCmp(&(tvc->fid), &(adp->fid))) {
1511 afs_PutVCache(*avcp);
1513 afs_PutFakeStat(&fakestate);
1514 return afs_CheckCode(EISDIR, &treq, 18);
1517 #endif /* AFS_OSF_ENV */
1520 afs_AddMarinerName(aname, tvc);
1522 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1523 if (!(flags & AFS_LOOKUP_NOEVAL))
1524 /* Here we don't enter the name into the DNLC because we want the
1525 evaluated mount dir to be there (the vcache for the mounted volume)
1526 rather than the vc of the mount point itself. we can still find the
1527 mount point's vc in the vcache by its fid. */
1528 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1530 osi_dnlc_enter (adp, aname, tvc, &versionNo);
1533 #ifdef AFS_LINUX20_ENV
1534 /* So Linux inode cache is up to date. */
1535 code = afs_VerifyVCache(tvc, &treq);
1537 afs_PutFakeStat(&fakestate);
1538 return 0; /* can't have been any errors if hit and !code */
1542 if (bulkcode) code = bulkcode; else
1543 code = afs_CheckCode(code, &treq, 19);
1545 /* If there is an error, make sure *avcp is null.
1546 * Alphas panic otherwise - defect 10719.
1551 afs_PutFakeStat(&fakestate);