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 "../afs/param.h" /* Should be always first */
23 #include "../afs/sysincludes.h" /* Standard vendor system headers */
24 #include "../afs/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"
33 * A few definitions. This is until we have a proper header file
34 * which has prototypes for all functions
37 extern struct DirEntry * afs_dir_GetBlob();
39 extern afs_rwlock_t afs_xvcache;
40 extern afs_rwlock_t afs_xcbhash;
41 extern struct afs_exporter *afs_nfsexporter;
42 extern char *afs_sysname;
43 extern char *afs_sysnamelist[];
44 extern int afs_sysnamecount;
45 extern struct afs_q VLRU; /*vcache LRU*/
46 #ifdef AFS_LINUX22_ENV
47 extern struct inode_operations afs_symlink_iops, afs_dir_iops;
51 afs_int32 afs_bulkStatsDone;
52 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
55 /* this would be faster if it did comparison as int32word, but would be
56 * dependant on byte-order and alignment, and I haven't figured out
57 * what "@sys" is in binary... */
58 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
62 register char *s1, *s2;
78 register char *a, c; {
80 AFS_STATCNT(afs_index);
82 if (tc == c) return a;
88 /* call under write lock, evaluate mvid field from a mt pt.
89 * avc is the vnode of the mount point object.
90 * advc is the vnode of the containing directory
91 * avolpp is where we return a pointer to the volume named by the mount pt, if success
92 * areq is the identity of the caller.
94 * NOTE: this function returns a held volume structure in *volpp if it returns 0!
96 EvalMountPoint(avc, advc, avolpp, areq)
97 register struct vcache *avc;
98 struct volume **avolpp;
99 struct vcache *advc; /* the containing dir */
100 register struct vrequest *areq;
103 struct volume *tvp = 0;
104 struct VenusFid tfid;
106 char *cpos, *volnamep;
108 afs_int32 prefetchRO; /* 1=>No 2=>Yes */
109 afs_int32 mtptCell, assocCell, hac=0;
110 afs_int32 samecell, roname, len;
112 AFS_STATCNT(EvalMountPoint);
114 if (avc->mvid && (avc->states & CMValid)) return 0; /* done while racing */
116 *avolpp = (struct volume *)0;
117 code = afs_HandleLink(avc, areq);
118 if (code) return code;
120 /* Determine which cell and volume the mointpoint goes to */
121 type = avc->linkData[0]; /* '#'=>Regular '%'=>RW */
122 cpos = afs_index(&avc->linkData[1], ':'); /* if cell name present */
126 tcell = afs_GetCellByName(&avc->linkData[1], READ_LOCK);
129 volnamep = &avc->linkData[1];
130 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
132 if (!tcell) return ENOENT;
134 mtptCell = tcell->cell; /* The cell for the mountpoint */
136 hac = 1; /* has associated cell */
137 assocCell = tcell->lcellp->cell; /* The associated cell */
139 afs_PutCell(tcell, READ_LOCK);
141 /* Is volume name a "<n>.backup" or "<n>.readonly" name */
142 len = strlen(volnamep);
143 roname = ((len > 9) && (strcmp(&volnamep[len - 9],".readonly") == 0)) ||
144 ((len > 7) && (strcmp(&volnamep[len - 7],".backup") == 0));
146 /* When we cross mountpoint, do we stay in the same cell */
147 samecell = (avc->fid.Cell == mtptCell) || (hac && (avc->fid.Cell == assocCell));
149 /* Decide whether to prefetch the RO. Also means we want the RO.
150 * If this is a regular mountpoint with a RW volume name and
151 * we cross a cell boundary -or- start from a RO volume, then we will
152 * want to prefetch the RO volume when we get the RW below.
154 if ( (type == '#') && !roname && (!samecell || (avc->states & CRO)) ) {
155 prefetchRO = 2; /* Yes, prefetch the RO */
157 prefetchRO = 1; /* No prefetch of the RO */
160 /* Get the volume struct. Unless this volume name has ".readonly" or
161 * ".backup" in it, this will get the volume struct for the RW volume.
162 * The RO volume will be prefetched if requested (but not returned).
164 tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetchRO, areq, WRITE_LOCK);
166 /* If no volume was found in this cell, try the associated linked cell */
167 if (!tvp && hac && areq->volumeError) {
168 tvp = afs_GetVolumeByName(volnamep, assocCell, prefetchRO, areq, WRITE_LOCK);
171 /* Still not found. If we are looking for the RO, then perhaps the RW
172 * doesn't exist? Try adding ".readonly" to volname and look for that.
173 * Don't know why we do this. Would have still found it in above call - jpm.
175 if (!tvp && (prefetchRO == 2)) {
176 strcpy(buf, volnamep);
177 afs_strcat(buf, ".readonly");
179 tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
181 /* Try the associated linked cell if failed */
182 if (!tvp && hac && areq->volumeError) {
183 tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
187 if (!tvp) return ENODEV; /* Couldn't find the volume */
189 /* Don't cross mountpoint from a BK to a BK volume */
190 if ((avc->states & CBackup) && (tvp->states & VBackup)) {
191 afs_PutVolume(tvp, WRITE_LOCK);
195 /* If we want (prefetched) the RO and it exists, then drop the
196 * RW volume and get the RO. Othewise, go with the RW.
198 if ((prefetchRO == 2) && tvp->roVol) {
199 tfid.Fid.Volume = tvp->roVol; /* remember RO volume */
200 tfid.Cell = tvp->cell;
201 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
202 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
203 if (!tvp) return ENODEV; /* oops, can't do it */
207 avc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
208 avc->mvid->Cell = tvp->cell;
209 avc->mvid->Fid.Volume = tvp->volume;
210 avc->mvid->Fid.Vnode = 1;
211 avc->mvid->Fid.Unique = 1;
212 avc->states |= CMValid;
214 /* Used to: if the mount point is stored within a backup volume,
215 * then we should only update the parent pointer information if
216 * there's none already set, so as to avoid updating a volume's ..
217 * info with something in an OldFiles directory.
219 * Next two lines used to be under this if:
221 * if (!(avc->states & CBackup) || tvp->dotdot.Fid.Volume == 0)
223 * Now: update mount point back pointer on every call, so that we handle
224 * multiple mount points better. This way, when du tries to go back
225 * via chddir(".."), it will end up exactly where it started, yet
226 * cd'ing via a new path to a volume will reset the ".." pointer
229 tvp->mtpoint = avc->fid; /* setup back pointer to mtpoint */
230 tvp->dotdot = advc->fid;
237 register char *aname; {
241 AFS_STATCNT(ENameOK);
242 tlen = strlen(aname);
243 if (tlen >= 4 && strcmp(aname+tlen-4, "@sys") == 0) return 0;
247 afs_getsysname(areq, adp, bufp)
248 register struct vrequest *areq;
249 register struct vcache *adp;
252 static char sysname[MAXSYSNAME];
253 register struct unixuser *au;
254 register afs_int32 error;
256 if (!afs_nfsexporter) {
257 strcpy(bufp, afs_sysname);
260 AFS_STATCNT(getsysname);
261 au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
264 error = EXP_SYSNAME(au->exporter, (char *)0, bufp);
266 strcpy(bufp, "@sys");
269 strcpy(bufp, afs_sysname);
274 Check_AtSys(avc, aname, state, areq)
275 register struct vcache *avc;
277 struct sysname_info *state;
278 struct vrequest *areq;
280 if (AFS_EQ_ATSYS(aname)) {
282 state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
284 state->index = afs_getsysname(areq, avc, state->name);
293 Next_AtSys(avc, areq, state)
294 register struct vcache *avc;
295 struct vrequest *areq;
296 struct sysname_info *state;
298 if (state->index == -1)
299 return 0; /* No list */
301 /* Check for the initial state of aname != "@sys" in Check_AtSys*/
302 if (state->offset == -1 && state->allocked == 0) {
303 register char *tname;
304 /* Check for .*@sys */
305 for (tname=state->name; *tname; tname++)
306 /*Move to the end of the string*/;
307 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
308 state->offset = (tname - 4) - state->name;
309 tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
310 strncpy(tname, state->name, state->offset);
313 state->index = afs_getsysname(areq, avc, state->name+state->offset);
316 return 0; /* .*@sys doesn't match either */
317 } else if (++(state->index) >= afs_sysnamecount
318 || !afs_sysnamelist[state->index])
319 return 0; /* end of list */
320 strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
324 #if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
325 extern int BlobScan(ino64_t *afile, afs_int32 ablob);
327 #if defined AFS_LINUX_64BIT_KERNEL
328 extern int BlobScan(long *afile, afs_int32 ablob);
330 extern int BlobScan(afs_int32 *afile, afs_int32 ablob);
335 /* called with an unlocked directory and directory cookie. Areqp
336 * describes who is making the call.
337 * Scans the next N (about 30, typically) directory entries, and does
338 * a bulk stat call to stat them all.
340 * Must be very careful when merging in RPC responses, since we dont
341 * want to overwrite newer info that was added by a file system mutating
342 * call that ran concurrently with our bulk stat call.
344 * We do that, as described below, by not merging in our info (always
345 * safe to skip the merge) if the status info is valid in the vcache entry.
347 * If adapt ever implements the bulk stat RPC, then this code will need to
348 * ensure that vcaches created for failed RPC's to older servers have the
351 struct vcache * BStvc = (struct vcache *) 0;
352 void afs_DoBulkStat(adp, dirCookie, areqp)
355 struct vrequest *areqp;
357 int nentries; /* # of entries to prefetch */
358 int nskip; /* # of slots in the LRU queue to skip */
359 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
360 struct dcache *dcp; /* chunk containing the dir block */
361 char *statMemp; /* status memory block */
362 char *cbfMemp; /* callback and fid memory block */
363 long temp; /* temp for holding chunk length, &c. */
364 struct AFSFid *fidsp; /* file IDs were collecting */
365 struct AFSCallBack *cbsp; /* call back pointers */
366 struct AFSCallBack *tcbp; /* temp callback ptr */
367 struct AFSFetchStatus *statsp; /* file status info */
368 struct AFSVolSync volSync; /* vol sync return info */
369 struct vcache *tvcp; /* temp vcp */
370 struct afs_q *tq; /* temp queue variable */
371 AFSCBFids fidParm; /* file ID parm for bulk stat */
372 AFSBulkStats statParm; /* stat info parm for bulk stat */
373 int fidIndex; /* which file were stating */
374 struct conn *tcp; /* conn for call */
375 AFSCBs cbParm; /* callback parm for bulk stat */
376 struct server *hostp = 0; /* host we got callback from */
377 long origEvenCBs; /* original # of callbacks for even-fid files */
378 long origOddCBs; /* original # of callbacks for odd-fid files */
379 long origEvenZaps; /* original # of recycles for even-fid files */
380 long origOddZaps; /* original # of recycles for odd-fid files */
381 long startTime; /* time we started the call,
382 * for callback expiration base
384 int statSeqNo; /* Valued of file size to detect races */
385 int code; /* error code */
386 long newIndex; /* new index in the dir */
387 struct DirEntry *dirEntryp; /* dir entry we are examining */
389 struct VenusFid afid; /* file ID we are using now */
390 struct VenusFid tfid; /* another temp. file ID */
391 afs_int32 retry; /* handle low-level SGI MP race conditions */
392 long volStates; /* flags from vol structure */
393 struct volume *volp=0; /* volume ptr */
394 struct VenusFid dotdot;
395 int flagIndex; /* First file with bulk fetch flag set */
398 /* first compute some basic parameters. We dont want to prefetch more
399 * than a fraction of the cache in any given call, and we want to preserve
400 * a portion of the LRU queue in any event, so as to avoid thrashing
401 * the entire stat cache (we will at least leave some of it alone).
402 * presently dont stat more than 1/8 the cache in any one call. */
403 nentries = afs_cacheStats / 8;
405 /* dont bother prefetching more than one calls worth of info */
406 if (nentries > AFSCBMAX) nentries = AFSCBMAX;
408 /* heuristic to make sure that things fit in 4K. This means that
409 * we shouldnt make it any bigger than 47 entries. I am typically
410 * going to keep it a little lower, since we don't want to load
411 * too much of the stat cache.
413 if (nentries > 30) nentries = 30;
415 /* now, to reduce the stack size, well allocate two 4K blocks,
416 * one for fids and callbacks, and one for stat info. Well set
417 * up our pointers to the memory from there, too.
419 statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
420 statsp = (struct AFSFetchStatus *) statMemp;
421 cbfMemp = osi_AllocLargeSpace(nentries *
422 (sizeof(AFSCallBack) + sizeof(AFSFid)));
423 fidsp = (AFSFid *) cbfMemp;
424 cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
426 /* next, we must iterate over the directory, starting from the specified
427 * cookie offset (dirCookie), and counting out nentries file entries.
428 * We skip files that already have stat cache entries, since we
429 * dont want to bulk stat files that are already in the cache.
432 code = afs_VerifyVCache(adp, areqp);
435 dcp = afs_GetDCache(adp, 0, areqp, &temp, &temp, 1);
441 /* lock the directory cache entry */
442 ObtainReadLock(&adp->lock);
445 * Make sure that the data in the cache is current. There are two
446 * cases we need to worry about:
447 * 1. The cache data is being fetched by another process.
448 * 2. The cache data is no longer valid
450 while ((adp->states & CStatd)
451 && (dcp->flags & DFFetching)
452 && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
453 dcp->flags |= DFWaiting;
454 ReleaseReadLock(&adp->lock);
455 afs_osi_Sleep(&dcp->validPos);
456 ObtainReadLock(&adp->lock);
458 if (!(adp->states & CStatd)
459 || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
460 ReleaseReadLock(&adp->lock);
465 /* Generate a sequence number so we can tell whether we should
466 * store the attributes when processing the response. This number is
467 * stored in the file size when we set the CBulkFetching bit. If the
468 * CBulkFetching is still set and this value hasn't changed, then
469 * we know we were the last to set CBulkFetching bit for this file,
470 * and it is safe to set the status information for this file.
472 statSeqNo = bulkStatCounter++;
474 /* now we have dir data in the cache, so scan the dir page */
477 while (1) { /* Should probably have some constant bound */
478 /* look for first safe entry to examine in the directory. BlobScan
479 * looks for a the 1st allocated dir after the dirCookie slot.
481 newIndex = BlobScan(&dcp->f.inode, (dirCookie>>5));
482 if (newIndex == 0) break;
484 /* remember the updated directory cookie */
485 dirCookie = newIndex << 5;
487 /* get a ptr to the dir entry */
488 dirEntryp =(struct DirEntry *)afs_dir_GetBlob(&dcp->f.inode, newIndex);
489 if (!dirEntryp) break;
491 /* dont copy more than we have room for */
492 if (fidIndex >= nentries) {
493 DRelease((char *) dirEntryp, 0);
497 /* now, if the dir entry looks good, copy it out to our list. Vnode
498 * 0 means deleted, although it should also be free were it deleted.
500 if (dirEntryp->fid.vnode != 0) {
501 /* dont copy entries we have in our cache. This check will
502 * also make us skip "." and probably "..", unless it has
503 * disappeared from the cache since we did our namei call.
505 tfid.Cell = adp->fid.Cell;
506 tfid.Fid.Volume = adp->fid.Fid.Volume;
507 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
508 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
511 ObtainWriteLock(&afs_xvcache, 130);
512 tvcp = afs_FindVCache(&tfid, 0, 0, &retry, 0 /* no stats | LRU */);
514 ReleaseWriteLock(&afs_xvcache);
517 } while (tvcp && retry);
518 if (!tvcp) { /* otherwise, create manually */
519 tvcp = afs_NewVCache(&tfid, hostp, 0, 0);
520 ObtainWriteLock(&tvcp->lock, 505);
521 ReleaseWriteLock(&afs_xvcache);
522 afs_RemoveVCB(&tfid);
523 ReleaseWriteLock(&tvcp->lock);
525 ReleaseWriteLock(&afs_xvcache);
528 goto done; /* can't happen at present, more's the pity */
530 /* WARNING: afs_DoBulkStat uses the Length field to store a
531 * sequence number for each bulk status request. Under no
532 * circumstances should afs_DoBulkStat store a sequence number
533 * if the new length will be ignored when afs_ProcessFS is
534 * called with new stats. */
536 if (!(tvcp->states & (CStatd|CBulkFetching))
537 && (tvcp->execsOrWriters <= 0)
538 && !afs_DirtyPages(tvcp)
539 && !AFS_VN_MAPPED((vnode_t*)tvcp))
541 if (!(tvcp->states & (CStatd|CBulkFetching))
542 && (tvcp->execsOrWriters <= 0)
543 && !afs_DirtyPages(tvcp))
547 /* this entry doesnt exist in the cache, and is not
548 * already being fetched by someone else, so add it to the
549 * list of file IDs to obtain.
551 * We detect a callback breaking race condition by checking the
552 * CBulkFetching state bit and the value in the file size.
553 * It is safe to set the status only if the CBulkFetching
554 * flag is still set and the value in the file size does
557 * Don't fetch status for dirty files. We need to
558 * preserve the value of the file size. We could
559 * flush the pages, but it wouldn't be worthwhile.
561 bcopy((char *) &tfid.Fid, (char *)(fidsp+fidIndex),
563 tvcp->states |= CBulkFetching;
564 tvcp->m.Length = statSeqNo;
568 } /* if dir vnode has non-zero entry */
570 /* move to the next dir entry by adding in the # of entries
571 * used by this dir entry.
573 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
574 DRelease((char *) dirEntryp, 0);
575 if (temp <= 0) break;
577 } /* while loop over all dir entries */
579 /* now release the dir lock and prepare to make the bulk RPC */
580 ReleaseReadLock(&adp->lock);
582 /* release the chunk */
585 /* dont make a null call */
586 if (fidIndex == 0) goto done;
589 /* setup the RPC parm structures */
590 fidParm.AFSCBFids_len = fidIndex;
591 fidParm.AFSCBFids_val = fidsp;
592 statParm.AFSBulkStats_len = fidIndex;
593 statParm.AFSBulkStats_val = statsp;
594 cbParm.AFSCBs_len = fidIndex;
595 cbParm.AFSCBs_val = cbsp;
597 /* start the timer; callback expirations are relative to this */
598 startTime = osi_Time();
600 tcp = afs_Conn(&adp->fid, areqp, SHARED_LOCK);
602 hostp = tcp->srvr->server;
603 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
604 #ifdef RX_ENABLE_LOCKS
606 #endif /* RX_ENABLE_LOCKS */
607 code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
609 #ifdef RX_ENABLE_LOCKS
611 #endif /* RX_ENABLE_LOCKS */
615 } while (afs_Analyze(tcp, code, &adp->fid, areqp,
616 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, (struct cell *)0));
618 /* now, if we didnt get the info, bail out. */
621 /* we need vol flags to create the entries properly */
622 dotdot.Fid.Volume = 0;
623 volp = afs_GetVolume(&adp->fid, areqp, READ_LOCK);
625 volStates = volp->states;
626 if (volp->dotdot.Fid.Volume != 0)
627 dotdot = volp->dotdot;
631 /* find the place to merge the info into We do this by skipping
632 * nskip entries in the LRU queue. The more we skip, the more
633 * we preserve, since the head of the VLRU queue is the most recently
637 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
638 ObtainReadLock(&afs_xvcache);
640 /* actually a serious error, probably should panic. Probably will
641 * panic soon, oh well. */
642 ReleaseReadLock(&afs_xvcache);
643 afs_warnuser("afs_DoBulkStat: VLRU empty!");
646 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
647 refpanic ("Bulkstat VLRU inconsistent");
649 for(tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
650 if (--nskip <= 0) break;
651 else if (QNext(QPrev(tq)) != tq) {
653 refpanic ("BulkStat VLRU inconsistent");
656 if (tq != &VLRU) lruvcp = QTOV(tq);
657 else lruvcp = QTOV(VLRU.next);
659 /* now we have to hold this entry, so that it does not get moved
660 * into the free list while we're running. It could still get
661 * moved within the lru queue, but hopefully that will be rare; it
662 * doesn't hurt nearly as much.
665 osi_vnhold(lruvcp, &retry);
666 ReleaseReadLock(&afs_xvcache); /* could be read lock */
670 /* otherwise, merge in the info. We have to be quite careful here,
671 * since we need to ensure that we don't merge old info over newer
672 * stuff in a stat cache entry. We're very conservative here: we don't
673 * do the merge at all unless we ourselves create the stat cache
674 * entry. That's pretty safe, and should work pretty well, since we
675 * typically expect to do the stat cache creation ourselves.
677 * We also have to take into account racing token revocations.
679 for(i=0; i<fidIndex; i++) {
680 afid.Cell = adp->fid.Cell;
681 afid.Fid.Volume = adp->fid.Fid.Volume;
682 afid.Fid.Vnode = fidsp[i].Vnode;
683 afid.Fid.Unique = fidsp[i].Unique;
686 ObtainReadLock(&afs_xvcache);
687 tvcp = afs_FindVCache(&afid, 1, 0, &retry, 0/* !stats&!lru*/);
688 ReleaseReadLock(&afs_xvcache);
689 } while (tvcp && retry);
691 /* The entry may no longer exist */
696 /* now we have the entry held, but we need to fill it in */
697 ObtainWriteLock(&tvcp->lock,131);
699 /* if CBulkFetching is not set, or if the file size no longer
700 * matches the value we placed there when we set the CBulkFetching
701 * flag, then someone else has done something with this node,
702 * and we may not have the latest status information for this
703 * file. Leave the entry alone.
705 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
707 ReleaseWriteLock(&tvcp->lock);
712 /* now copy ".." entry back out of volume structure, if necessary */
713 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
715 tvcp->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
716 *tvcp->mvid = dotdot;
719 ObtainWriteLock(&afs_xvcache,132);
720 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
721 refpanic ("Bulkstat VLRU inconsistent2");
723 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
724 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
725 refpanic ("Bulkstat VLRU inconsistent4");
726 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
727 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
728 refpanic ("Bulkstat VLRU inconsistent5");
730 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
731 QRemove(&tvcp->vlruq);
732 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
735 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
736 refpanic ("Bulkstat VLRU inconsistent3");
738 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
739 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
740 refpanic ("Bulkstat VLRU inconsistent5");
741 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
742 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
743 refpanic ("Bulkstat VLRU inconsistent6");
744 ReleaseWriteLock(&afs_xvcache);
746 ObtainWriteLock(&afs_xcbhash, 494);
748 /* We need to check the flags again. We may have missed
749 * something while we were waiting for a lock.
751 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
753 ReleaseWriteLock(&tvcp->lock);
754 ReleaseWriteLock(&afs_xcbhash);
759 /* now merge in the resulting status back into the vnode.
760 * We only do this if the entry looks clear.
762 afs_ProcessFS(tvcp, &statsp[i], areqp);
763 #ifdef AFS_LINUX22_ENV
764 /* overwrite the ops if it's a directory or symlink. */
765 if (vType(tvcp) == VDIR)
766 tvcp->v.v_op = &afs_dir_iops;
767 else if (vType(tvcp) == VLNK)
768 tvcp->v.v_op = &afs_symlink_iops;
771 /* do some accounting for bulk stats: mark this entry as
772 * loaded, so we can tell if we use it before it gets
775 tvcp->states |= CBulkStat;
776 tvcp->states &= ~CBulkFetching;
780 /* merge in vol info */
781 if (volStates & VRO) tvcp->states |= CRO;
782 if (volStates & VBackup) tvcp->states |= CBackup;
783 if (volStates & VForeign) tvcp->states |= CForeign;
785 /* merge in the callback info */
786 tvcp->states |= CTruth;
788 /* get ptr to the callback we are interested in */
791 if (tcbp->ExpirationTime != 0) {
792 tvcp->cbExpires = tcbp->ExpirationTime+startTime;
793 tvcp->callback = hostp;
794 tvcp->states |= CStatd;
795 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
797 else if (tvcp->states & CRO) {
798 /* ordinary callback on a read-only volume -- AFS 3.2 style */
799 tvcp->cbExpires = 3600+startTime;
800 tvcp->callback = hostp;
801 tvcp->states |= CStatd;
802 afs_QueueCallback(tvcp, CBHash(3600), volp);
806 tvcp->states &= ~(CStatd|CUnique);
807 afs_DequeueCallback(tvcp);
808 if ((tvcp->states & CForeign) || (vType(tvcp) == VDIR))
809 osi_dnlc_purgedp (tvcp); /* if it (could be) a directory */
811 ReleaseWriteLock(&afs_xcbhash);
813 ReleaseWriteLock(&tvcp->lock);
814 /* finally, we're done with the entry */
816 } /* for all files we got back */
818 /* finally return the pointer into the LRU queue */
819 afs_PutVCache(lruvcp);
822 /* Be sure to turn off the CBulkFetching flags */
823 for(i=flagIndex; i<fidIndex; i++) {
824 afid.Cell = adp->fid.Cell;
825 afid.Fid.Volume = adp->fid.Fid.Volume;
826 afid.Fid.Vnode = fidsp[i].Vnode;
827 afid.Fid.Unique = fidsp[i].Unique;
830 ObtainReadLock(&afs_xvcache);
831 tvcp = afs_FindVCache(&afid, 1, 0, &retry, 0/* !stats&!lru*/);
832 ReleaseReadLock(&afs_xvcache);
833 } while (tvcp && retry);
835 && (tvcp->states & CBulkFetching)
836 && (tvcp->m.Length == statSeqNo)) {
837 tvcp->states &= ~CBulkFetching;
844 afs_PutVolume(volp, READ_LOCK);
846 osi_FreeLargeSpace(statMemp);
847 osi_FreeLargeSpace(cbfMemp);
850 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
856 struct nameidata *ndp; {
857 char aname[MAXNAMLEN+1]; /* XXX */
858 struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
859 struct ucred *acred = ndp->ni_cred;
860 int wantparent = ndp->ni_nameiop & WANTPARENT;
861 int opflag = ndp->ni_nameiop & OPFLAG;
862 #else /* AFS_OSF_ENV */
863 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
864 afs_lookup(OSI_VC_ARG(adp), aname, avcp, pnp, flags, rdir, acred)
865 struct pathname *pnp;
870 afs_lookup(adp, aname, avcp, acred, flags)
873 afs_lookup(adp, aname, avcp, acred)
875 #endif /* SUN5 || SGI */
877 struct vcache **avcp;
879 struct AFS_UCRED *acred; {
881 struct vrequest treq;
882 char *tname = (char *)0;
883 register struct vcache *tvc=0;
884 register afs_int32 code;
885 int pass = 0, hit = 0;
887 extern afs_int32 afs_mariner; /*Writing activity to log?*/
889 afs_hyper_t versionNo;
890 int no_read_access = 0;
891 struct sysname_info sysState; /* used only for @sys checking */
893 AFS_STATCNT(afs_lookup);
895 ndp->ni_dvp = (struct vnode *)adp;
896 bcopy(ndp->ni_ptr, aname, ndp->ni_namelen);
897 aname[ndp->ni_namelen] = '\0';
898 #endif /* AFS_OSF_ENV */
900 *avcp = (struct vcache *) 0; /* Since some callers don't initialize it */
902 if (code = afs_InitReq(&treq, acred)) {
906 /* come back to here if we encounter a non-existent object in a read-only
907 volume's directory */
910 *avcp = (struct vcache *) 0; /* Since some callers don't initialize it */
912 if (!(adp->states & CStatd)) {
913 if (code = afs_VerifyVCache2(adp, &treq))
918 /* watch for ".." in a volume root */
919 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
920 /* looking up ".." in root via special hacks */
921 if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
923 extern struct vcache *afs_globalVp;
924 if (adp == afs_globalVp) {
925 struct vnode *rvp = (struct vnode *)adp;
927 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
928 ndp->ni_dvp = ndp->ni_vp;
938 /* otherwise we have the fid here, so we use it */
939 tvc = afs_GetVCache(adp->mvid, &treq, (afs_int32 *)0,
940 (struct vcache*)0, 0);
941 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT,
942 ICL_TYPE_FID, adp->mvid, ICL_TYPE_POINTER, tvc,
943 ICL_TYPE_INT32, code);
945 code = (tvc ? 0 : ENOENT);
947 if (tvc && !tvc->vrefCount) {
951 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code);*/
956 /* now check the access */
957 if (treq.uid != adp->last_looker) {
958 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
959 *avcp = (struct vcache *)0;
963 else adp->last_looker = treq.uid;
966 /* Check for read access as well. We need read access in order to
967 stat files, but not to stat subdirectories. */
968 if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
971 /* special case lookup of ".". Can we check for it sooner in this code,
972 * for instance, way up before "redo:" ??
973 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
974 * invent a lightweight version of GetVCache.
976 if (aname[0] == '.' && !aname[1]) { /* special case */
977 ObtainReadLock(&afs_xvcache);
979 ReleaseReadLock(&afs_xvcache);
983 if (adp && !adp->vrefCount) {
989 Check_AtSys(adp, aname, &sysState, &treq);
990 tname = sysState.name;
992 /* 1st Check_AtSys and lookup by tname is required here, for now,
993 because the dnlc is *not* told to remove entries for the parent
994 dir of file/dir op that afs_LocalHero likes, but dnlc is informed
995 if the cached entry for the parent dir is invalidated for a
997 Otherwise, we'd be able to do a dnlc lookup on an entry ending
998 w/@sys and know the dnlc was consistent with reality. */
999 tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
1000 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1002 if (no_read_access && vType(tvc) != VDIR) {
1003 /* need read access on dir to stat non-directory */
1004 afs_PutVCache(tvc, WRITE_LOCK);
1005 *avcp = (struct vcache *)0;
1009 #ifdef AFS_LINUX22_ENV
1010 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1019 #else /* non - LINUX */
1023 #endif /* linux22 */
1027 register struct dcache *tdc;
1028 afs_int32 dirOffset, dirLen;
1030 struct VenusFid tfid;
1032 /* now we have to lookup the next fid */
1033 tdc = afs_GetDCache(adp, 0, &treq, &dirOffset, &dirLen, 1);
1035 *avcp = (struct vcache *)0; /* redundant, but harmless */
1040 /* now we will just call dir package with appropriate inode.
1041 Dirs are always fetched in their entirety for now */
1042 ObtainReadLock(&adp->lock);
1045 * Make sure that the data in the cache is current. There are two
1046 * cases we need to worry about:
1047 * 1. The cache data is being fetched by another process.
1048 * 2. The cache data is no longer valid
1050 while ((adp->states & CStatd)
1051 && (tdc->flags & DFFetching)
1052 && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1053 tdc->flags |= DFWaiting;
1054 ReleaseReadLock(&adp->lock);
1055 afs_osi_Sleep(&tdc->validPos);
1056 ObtainReadLock(&adp->lock);
1058 if (!(adp->states & CStatd)
1059 || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1060 ReleaseReadLock(&adp->lock);
1065 /* Save the version number for when we call osi_dnlc_enter */
1066 hset(versionNo, tdc->f.versionNo);
1069 * check for, and handle "@sys" if it's there. We should be able
1070 * to avoid the alloc and the strcpy with a little work, but it's
1071 * not pressing. If there aren't any remote users (ie, via the
1072 * NFS translator), we have a slightly easier job.
1073 * the faster way to do this is to check for *aname == '@' and if
1074 * it's there, check for @sys, otherwise, assume there's no @sys
1075 * then, if the lookup fails, check for .*@sys...
1077 /* above now implemented by Check_AtSys and Next_AtSys */
1079 /* lookup the name in the appropriate dir, and return a cache entry
1080 on the resulting fid */
1081 theDir = tdc->f.inode;
1082 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1084 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1085 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
1086 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1088 tname = sysState.name;
1090 ReleaseReadLock(&adp->lock);
1093 /* new fid has same cell and volume */
1094 tfid.Cell = adp->fid.Cell;
1095 tfid.Fid.Volume = adp->fid.Fid.Volume;
1096 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1097 ICL_TYPE_STRING, tname,
1098 ICL_TYPE_FID, &tfid, ICL_TYPE_INT32, code);
1101 if (code != ENOENT) {
1102 printf("LOOKUP dirLookupOff -> %d\n", code);
1107 /* prefetch some entries, if the dir is currently open. The variable
1108 * dirCookie tells us where to start prefetching from.
1110 if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)) {
1112 /* if the entry is not in the cache, or is in the cache,
1113 * but hasn't been statd, then do a bulk stat operation.
1117 ObtainReadLock(&afs_xvcache);
1118 tvc = afs_FindVCache(&tfid, 1, 0, &retry, 0/* !stats,!lru */);
1119 ReleaseReadLock(&afs_xvcache);
1120 } while (tvc && retry);
1122 if (!tvc || !(tvc->states & CStatd)) {
1123 afs_DoBulkStat(adp, dirCookie, &treq);
1126 /* if the vcache isn't usable, release it */
1127 if (tvc && !(tvc->states & CStatd)) {
1129 tvc = (struct vcache *) 0;
1132 else tvc = (struct vcache *) 0;
1134 /* now get the status info, if we don't already have it */
1135 /* This is kind of weird, but we might wind up accidentally calling
1136 * RXAFS_Lookup because we happened upon a file which legitimately
1137 * has a 0 uniquifier. That is the result of allowing unique to wrap
1138 * to 0. This was fixed in AFS 3.4. For CForeigh, Unique == 0 means that
1139 * the file has not yet been looked up.
1142 afs_int32 cached = 0;
1143 if (!tfid.Fid.Unique && (adp->states & CForeign)) {
1144 tvc = afs_LookupVCache(&tfid, &treq, &cached, WRITE_LOCK,
1147 if (!tvc) { /* lookup failed or wasn't called */
1148 tvc = afs_GetVCache(&tfid, &treq, &cached, (struct vcache*)0,
1152 } /* sub-block just to reduce stack usage */
1155 if (adp->states & CForeign)
1156 tvc->states |= CForeign;
1157 tvc->parentVnode = adp->fid.Fid.Vnode;
1158 tvc->parentUnique = adp->fid.Fid.Unique;
1159 tvc->states &= ~CBulkStat;
1161 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1162 if (!(flags & AFS_LOOKUP_NOEVAL))
1163 /* don't eval mount points */
1164 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1165 if (tvc->mvstat == 1) {
1166 /* a mt point, possibly unevaluated */
1167 struct volume *tvolp;
1169 ObtainWriteLock(&tvc->lock,133);
1170 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1171 ReleaseWriteLock(&tvc->lock);
1174 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1178 /* next, we want to continue using the target of the mt point */
1179 if (tvc->mvid && (tvc->states & CMValid)) {
1181 /* now lookup target, to set .. pointer */
1182 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1183 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID, &tvc->fid);
1184 uvc = tvc; /* remember for later */
1186 if (tvolp && (tvolp->states & VForeign)) {
1187 /* XXXX tvolp has ref cnt on but not locked! XXX */
1188 tvc = afs_GetRootVCache(tvc->mvid, &treq, (afs_int32 *)0, tvolp, WRITE_LOCK);
1190 tvc = afs_GetVCache(tvc->mvid, &treq, (afs_int32 *)0,
1191 (struct vcache*)0, WRITE_LOCK);
1193 afs_PutVCache(uvc, WRITE_LOCK); /* we're done with it */
1198 afs_PutVolume(tvolp, WRITE_LOCK);
1203 /* now, if we came via a new mt pt (say because of a new
1204 * release of a R/O volume), we must reevaluate the ..
1205 * ptr to point back to the appropriate place */
1207 ObtainWriteLock(&tvc->lock,134);
1208 if (tvc->mvid == (struct VenusFid *) 0) {
1209 tvc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
1211 /* setup backpointer */
1212 *tvc->mvid = tvolp->dotdot;
1213 ReleaseWriteLock(&tvc->lock);
1214 afs_PutVolume(tvolp, WRITE_LOCK);
1218 afs_PutVCache(tvc, WRITE_LOCK);
1220 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1225 if (tvc && !tvc->vrefCount) {
1231 /* if we get here, we found something in a directory that couldn't
1232 be located (a Multics "connection failure"). If the volume is
1233 read-only, we try flushing this entry from the cache and trying
1237 tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
1239 if (tv->states & VRO) {
1240 pass = 1; /* try this *once* */
1241 ObtainWriteLock(&afs_xcbhash, 495);
1242 afs_DequeueCallback(adp);
1243 /* re-stat to get later version */
1244 adp->states &= ~CStatd;
1245 ReleaseWriteLock(&afs_xcbhash);
1246 osi_dnlc_purgedp(adp);
1247 afs_PutVolume(tv, READ_LOCK);
1250 afs_PutVolume(tv, READ_LOCK);
1257 /* put the network buffer back, if need be */
1258 if (tname != aname && tname) osi_FreeLargeSpace(tname);
1261 /* Handle RENAME; only need to check rename "." */
1262 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1263 if (!FidCmp(&(tvc->fid), &(adp->fid))) {
1264 afs_PutVCache(*avcp, WRITE_LOCK);
1266 return afs_CheckCode(EISDIR, &treq, 18);
1269 #endif /* AFS_OSF_ENV */
1272 afs_AddMarinerName(aname, tvc);
1274 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1275 if (!(flags & AFS_LOOKUP_NOEVAL))
1276 /* Here we don't enter the name into the DNLC because we want the
1277 evaluated mount dir to be there (the vcache for the mounted volume)
1278 rather than the vc of the mount point itself. we can still find the
1279 mount point's vc in the vcache by its fid. */
1280 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1282 osi_dnlc_enter (adp, aname, tvc, &versionNo);
1285 #ifdef AFS_LINUX20_ENV
1286 /* So Linux inode cache is up to date. */
1287 code = afs_VerifyVCache(tvc, &treq);
1289 return 0; /* can't have been any errors if hit and !code */
1293 code = afs_CheckCode(code, &treq, 19);
1295 /* If there is an error, make sure *avcp is null.
1296 * Alphas panic otherwise - defect 10719.
1298 *avcp = (struct vcache *)0;